Reference

Version Policy

How org policy constrains allowed runtime and tool versions without turning on provisioning.

referenceautomation buildersintermediatestable2026-05-30

When to use this page

Use this page when a repo should stay explicit about what it needs, but the org wants to constrain which versions may be declared.

Use version_policy when governance matters even if installs stay manual or come from another bootstrap path.

  • the contract says what the repo needs
  • version_policy says which versions are allowed
  • provisioning says where ota may install or select that prerequisite
  • adapter_bootstrap only bootstraps the installer itself

How policy is interpreted

Think of policy as an approval gate. It validates what the repo declares; it does not rewrite repo requirements.

  • version_policy is keyed by runtimes and tools using the same names as ota.yaml.
  • Each policy entry may have approved_versions and optional platforms overrides.
  • A policy match is required on the active OS only; if a prerequisite is off on that OS via only_on, policy is not evaluated for that prerequisite.
  • Each approval entry is compared against the contract version expression with semver-aware rules; an unapproved expression is a hard policy failure.
  • If no matching policy entry exists, there is no version-policy gate for that prerequisite.
  • Policy can reject a declaration before provisioning, but it never changes version, provider, or distribution in the contract.

Current boundary

Repo contract

Declare runtime and tool intent in ota.yaml, including only_on for OS scope, platforms for per-OS value overrides, and required: false when a prerequisite should warn instead of block.

policies.version_policy

Constrain the versions governed repos may declare without forcing ota-managed installs.

policies.provisioning

Select the approved install source only when ota is also allowed to provision the prerequisite.

policies.adapter_bootstrap

Approve how ota may install the adapter binary if the chosen provisioning backend is missing.

Exact pin example

  • node: "22" passes and node: "24" fails
  • pnpm: "10.12.4" passes and pnpm: "10.12.5" fails
  • this is the strictest form because the org is enumerating one accepted contract version
ota.yamlyaml
version: 1project:  name: exampleruntimes:  node: "22"tools:  pnpm: "10.12.4"
.ota/org-policy.yamlyaml
policies:  version_policy:    runtimes:      node:        approved_versions:          - "22"    tools:      pnpm:        approved_versions:          - "10.12.4"

Semver-range example

  • use ranges when the org wants one compatible version family instead of one exact patch
  • keep the policy explicit enough that repo maintainers can still tell which version families are acceptable
  • doctor should fail when the repo declares a version outside the approved family
ota.yamlyaml
runtimes:  node: "22"tools:  pnpm: "^10"
.ota/org-policy.yamlyaml
policies:  version_policy:    runtimes:      node:        approved_versions:          - "22"    tools:      pnpm:        approved_versions:          - "^10"

OS-scoped example

Use only_on in the contract for OS scope, keep platforms in the contract or version_policy for per-OS overrides, and use required only for blocking-versus-warning behavior.

  • Windows may require pwsh 7.6.0
  • Linux and macOS do not fail readiness or policy checks if pwsh is inactive there
  • the same contract stays honest across different target OSes instead of pretending one host shape fits every machine
ota.yamlyaml
tools:  pwsh:    version: "7.6.0"    only_on:      - windows
.ota/org-policy.yamlyaml
policies:  version_policy:    tools:      pwsh:        platforms:          windows:            approved_versions:              - "7.6.0"

Java distribution example

Java is the clearest case for separating repo intent from org governance, because version, provider, distribution, and install source can all differ without meaning the same thing.

Use the contract to say what the repo expects, then use org policy to constrain the allowed version and approved install path for each target OS.

  • version: "21" says the repo expects Java 21, not just any installed JDK
  • provider: sdkman is repo intent about the runtime manager surface, not the same thing as a provisioning source approval
  • distribution: temurin is the default runtime flavor, while platforms.windows.distribution: zulu narrows the Windows expectation without changing macOS
  • only_on says Java is required on Windows and macOS but not on Linux for this repo
  • the org policy separately constrains the allowed Java version and the approved install source for each target OS
  • if the repo later asks for Java 22, doctor should report a version-policy violation before provisioning is even relevant
  • if the repo asks for zulu but policy only permits an OpenJDK provisioning path, that mismatch should stay explicit instead of being silently rewritten
ota.yamlyaml
runtimes:  java:    version: "21"    provider: sdkman    distribution: temurin    only_on:      - windows      - macos    platforms:      windows:        distribution: zulu
.ota/org-policy.yamlyaml
policies:  version_policy:    runtimes:      java:        approved_versions:          - "21"        platforms:          windows:            approved_versions:              - "21"   provisioning:    java:      source: sdkman      approved_versions:        - "21"      platforms:        windows:          source: winget          package: Microsoft.OpenJDK.21          approved_versions:            - "21"

With provisioning

Use both layers when the org wants to govern the allowed contract versions and also govern where ota may install them from.

  • version_policy is the contract governance layer
  • provisioning is the install-source selection layer
  • keep them separate so doctor can explain whether the repo asked for the wrong version or whether the approved source path is missing or blocked
.ota/org-policy.yamlyaml
policies:  version_policy:    runtimes:      node:        approved_versions:          - "22"    tools:      pnpm:        approved_versions:          - "10.12.4"   provisioning:    node:      source: choco      package: nodejs      approved_versions:        - "22"    pnpm:      source: npm      approved_versions:        - "10.12.4"

How doctor explains a failure

  • a version-policy failure is a contract-versus-policy mismatch
  • it is not the same thing as missing provisioning or a broken package manager
  • the next step should point maintainers to change the repo contract version or intentionally widen policy
Example findingtext
◉ ERROR  Repo does not satisfy org policy packWhy: `.ota/org-policy.yaml` requires version policy violations: runtime `node` version `24` is not approved by policy; expected one of: 22Next: update the repo contract versions or widen `.ota/org-policy.yaml`

When this is the right boundary

  • use version_policy when you want the org to control what versions are acceptable
  • use provisioning separately when the org must also control where missing prerequisites come from
  • skip both if your repo policy is purely convention and not a mandatory compliance control
  • when both are present, keep version-policy checks in front of provisioning decisions so failures stay explainable