Versioning and compatibility

What a Nistor version number promises: release trains, semantic versioning, the core API and deprecations.

What is versioned together#

Train Contains Tag
platform nistor-core, nistor-aggregations, nistor-platform-gcp, nistor-cli, nistor-mcp, nistor-testing, the services, the open-source plugins, @nistor-io/ui, @nistor-io/plugin-sdk and the shell image vX.Y.Z
tool one tool, nistor-tool-<id> tool-<id>/vA.B.C
plugin one commercial plugin, nistor-plugin-<id>, released from its own repository plugin-<id>/vA.B.C

The platform train has one version: all its members carry the same number and pin each other exactly. Each tool and each plugin has its own version and declares the range of nistor-core it works with.

Tags and files#

Versions are written statically in the files; nistor release prepare <train> <version> writes them, and the tag pipeline's first job (nistor release verify-tag <tag>) fails unless the files carry the tag's version.

A release candidate appends -rc.N (N is 1 or more). The tag spells it v1.0.0-rc.1; Python files spell it in PEP 440, 1.0.0rc1; npm files spell it in semver, 1.0.0-rc.1. nistor release parse-tag <tag> prints the train and the version.

The first public release is the platform 1.0.0, preceded by 1.0.0-rc.1; every tool starts at 1.0.0.

A release's notes are written into its train's CHANGELOG.md by nistor release changelog, from the commit subjects since the train's previous tag. A train's first release has no previous tag, so its notes are hand-written instead and committed as release/notes/<train>-<X.Y.Z>.md (platform-1.0.0.md, tool-gcp-1.0.0.md; the release candidates of that version read the same file). The file holds the body only, with ### headings at most and no relative links, since it lands in the CHANGELOG.md and the release page. Every later release takes its notes from the subjects again.

Semantic versioning#

The contracts follow semantic versioning:

  • A patch release fixes bugs only.
  • A minor release may add: optional members, new facts, new entry-point groups, new settings with defaults. It never removes or changes what exists.
  • A major release may remove, but only what a previous minor deprecated.

The core API#

CORE_API is the version of the tool and plugin contract, (major, minor), read from nistor_core.spi. It is versioned separately from the package. A tool or plugin declares requires_core_api as a version specifier on it. The major number changes only when the contract breaks.

What each minor added (a tool or plugin that uses an addition declares at least that minor):

  • 1.1: PluginManifest.enforcing_middleware, and the names nistor_core.api publishes beyond 1.0.
  • 1.2: ActivationDecision.valid_until.
  • 1.3: log_extension_query_labels in nistor_core.api (the log extensions' query labels, which the GCP tool's audit-log adapter stamps on ingest); ToolDescriptor.required_roles, the roles a customer grants a tool's connection (nistor-core 0.4.3); and nistor.usage_reporters, the usage-reporter SPI (nistor_core.spi.usage): the jobs role hands each installed reporter a deployment's aggregate usage counters every hour. Open-source distributions install no reporter. The runtime-platform names nistor_core.api publishes (runtime_deployed_service_name, runtime_is_deployed, runtime_is_job, runtime_service_revision, from nistor_core.general.runtime_platform): what the process runs on (Cloud Run or Kubernetes), read the same way on both.
  • 1.4: the module nistor_core.spi.legacy_names, the legacy spellings a tool reads or writes while both spellings are accepted (see Legacy names). PermissionFinding.missing_right_entries: the missing rights of a permission check as a structured list (MissingRightEntry: object_id, object_type, right, detail). Writers fill it and, until 2.0, also the JSON-string form missing_rights; readers prefer the entries and still read a fact that carries only the strings.

Runner tag#

Every CI job takes its runner from the CI/CD variable NISTOR_RUNNER_TAG (default nistor-gcp, the tag of the nistor group's own runner). In a project whose namespace has no such runner, such as the public project, set NISTOR_RUNNER_TAG in the project's Settings, CI/CD, Variables to the tag of a runner that project can use; the tag pipeline and the release jobs follow it. Never set it empty: an empty or blank NISTOR_RUNNER_TAG would leave every job untagged, so the pipeline's first workflow rule refuses to create a pipeline at all.

Deprecation window#

Something deprecated stays for at least one minor release, with a warning and a note in the changelog, before a major release removes it. A removal in a major release is listed in that release's notes, in a "Removed" section.

Legacy names#

Before 1.0 the product had another name, and its spelling reached stored values, columns, API fields, routes, job labels and infrastructure names. Two consecutive releases retire it, as any rename of a persisted or wire value must be: the expand reads both spellings and keeps writing the old one (the release before it still reads every row), the contract rewrites the stored values and refuses the old spellings. The changelog lists what each of the two releases changes. scripts/ci/legacy_names_map.json maps every class to its new spelling and status.

These stay for ever (scripts/ci/legacy_names_frozen.json, each entry with its reason):

  • The asset URN namespace. Every stored node id, lineage edge and history reference uses it, in every deployment and in users' contracts; renaming it would rewrite all of them. The parser, minting and stored ids are unchanged.
  • The bytes of recorded migration revisions. They are checksummed and never change; later revisions do the renames.
  • Reading text written outside Nistor before 1.0. Merge requests carrying the former rule-request marker and ODCS contracts carrying the former node-id property stay readable. Nistor only writes the new spellings.
  • Guard spellings. The guards and their tests spell the former name split across two literals to find it.

No new persisted value, column, index, API field, route, label or infrastructure name may carry the former name. The guard enforces it in CI (scripts/ci/repo_guards.sh):

python3 scripts/ci/check_brand_tokens.py --root . --allowlist scripts/ci/brand_tokens_allowlist.json --frozen scripts/ci/legacy_names_frozen.json --split-literals --max 0

--split-literals also finds the name spelt in two halves outside migrations and the one legacy-literals module. Between the two releases, the allowlist holds the reviewed entries the expand still needs; after the contract only the frozen list remains.

Compatibility checks#

The conformance kit (Writing a tool) is run in CI against the current core and also against the previous published core minor (the N-1 job, compat-previous-core), with the tree's tools installed beside it, so a tool never needs more than the nistor-core range it declares. The job waits, and passes, until a previous minor is published and the package names are claimed.

Supported versions#

Line Fixes
The latest minor of the current major every fix
The previous minor security fixes only, for 6 months after the next minor's release date
Anything older none: upgrade first (upgrading)

SECURITY.md lists the lines supported today. A tool follows only its own latest minor: it declares the nistor-core range it works with, so a fix to a tool ships as a new release of that tool.

Backports#

A fix lands on main first. A release/X.Y branch is cut from the vX.Y.Z tag only when a security fix has to reach the previous minor; release/* branches are protected (maintainers only). On that branch:

  1. cherry-pick the fix from main with git cherry-pick -x, through a merge request into release/X.Y;
  2. write the patch version with nistor release prepare platform X.Y.(Z+1);
  3. tag vX.Y.(Z+1) on the branch.

The tag runs the same release pipeline as a tag on main: the release rules ask for a protected tag, whatever branch it is on. Nothing but security fixes is backported, and a minor older than the previous one gets no backport.

Distributions#

The open-source distribution nistor-oss (distributions/oss/) is versioned with the platform: the platform tag locks it, and its lock is an asset of that release. The commercial distribution follows the same support window.

Edit this page on GitLab

↑ ↓ to moveEnter to openEsc to close