Skip to content

Continuous Integration And Release Contract

Assertions

CIR-001 - Workflow topology is event-driven and immutable

Contract: The repository MUST contain only CI, dependency submission, Pages, PR-body, and release workflows. Every GitHub-hosted job MUST run on ubuntu-26.04; external actions MUST use full commit SHAs; validator images MUST use immutable digests; checkout credentials MUST not persist; and every workflow MUST declare permissions and concurrency.

Evidence:

CIR-002 - Quality, compatibility, package, and OpenSSH remain visible gates

Contract: Reusable CI MUST assign source/policy, compatibility/coverage, distribution, hermetic OpenSSH, dependency review with an every-event exact-lock audit, Python and Actions CodeQL, and version progression to visible scoped jobs. Compatibility MUST run once for each declared Python minor; every other expensive gate MUST run once per invocation. No umbrella job MAY repeat another job's tests or build.

Evidence:

CIR-003 - Write permissions are job-scoped

Contract: Default workflow permission MUST be read-only contents. Only CodeQL MAY write security events, dependency submission MAY write contents, Pages deploy MAY write Pages and OIDC, PR-body automation MAY write pull requests, PyPI publication MAY write OIDC, and final GitHub publication MAY write contents. Each exception MUST be confined to its owning job.

Evidence:

CIR-004 - PR-body automation treats head content as bounded data

Contract: PR-body automation MUST be the only pull_request_target boundary, run only for pull requests that change CHANGELOG.md, execute only trusted default-branch code, read a bounded head changelog through the API as inert data, preserve manual body text, and refuse concurrent overwrite. It MUST select the newest populated level-two section, including Unreleased without a version change, and reject malformed or reserved managed markers.

Evidence:

CIR-005 - Version progression compares exact base and head

Contract: Pull requests and later main pushes MUST compare the exact base and proposed .version values. The first repository commit MAY compare against 0.0.0. Ordinary maintenance MAY retain an already published stable version while Unreleased accumulates. A changed version MUST advance beyond the exact base. Same-version unpublished recovery MUST advance beyond the latest stable release; drafts and prereleases MUST NOT count as published stable versions.

Evidence:

CIR-006 - Publication builds once and never replaces conflict

Contract: Reusable CI's distribution job MUST build and smoke the wheel/sdist once and, for the trusted release caller only, upload that exact pair as one immutable workflow artifact. No other maintained workflow MAY set that upload input. Release jobs MUST consume it without any rebuild for PyPI and GitHub. Published or draft tags, targets, notes, metadata, asset names, sizes, and hashes MUST be verified; conflict MUST fail without moving tags, deleting assets, or overwriting files.

Every direct-main push MUST first inspect both publication targets. An exact complete published release MUST skip reusable release CI and both publication jobs, even when main has advanced. Published version, notes, and target metadata MUST be validated against the immutable tagged source; draft recovery MUST remain tied to the current release commit. Missing tags and incomplete or conflicting publication state MUST fail closed.

Evidence:

CIR-007 - Dependency submission is trusted-main-only

Contract: Dependency submission MUST trigger only on direct main pushes that change dependency ownership, a lock, or snapshot automation; derive and validate all four manifests offline; verify the expected repository and payload shape; and use only its job-scoped standard token and contents write.

Evidence:

CIR-008 - Documentation changes build before merge and deploy from main

Contract: Documentation and docs-tool changes MUST trigger a strict non-deploying Pages build on pull requests. Direct main builds MUST audit routes, links, anchors, assets, canonical URLs, sitemap XML/gzip, robots, root files, and the absence of insecure HTTP references before a deploy job receives Pages and OIDC writes.

Evidence:

CIR-009 - Contract evidence is machine-checked

Contract: Contract files MUST be the only normative documentation, MUST use unique sequential IDs, and MUST link every assertion to at least one existing test definition. User, maintenance, and site-only inputs MUST remain separate, and every relative documentation link MUST resolve.

Evidence:

CIR-010 - Repository ownership is explicit

Contract: CODEOWNERS MUST assign every repository path to @kogeler, so a default-branch ruleset can require code-owner review for every change.

Evidence:

CIR-011 - PyPI publication is secretless, exact, and recoverable

Contract: Release state MUST inspect PyPI and GitHub independently. A missing PyPI version MUST publish only the gated wheel/sdist through the pypi Environment, PyPI Trusted Publishing, a job-scoped OIDC token, and the pinned official PyPA action. Stored credentials and blind duplicate skipping MUST be absent. Existing PyPI files MUST match local names, types, sizes, hashes, and yanked state before GitHub recovery continues.

Evidence:

CIR-012 - Mutable pins have executable owners

Contract: Project versions, dependency pins, action commits, image digests, runner labels, and release conventions MUST be owned by the executable configuration that consumes them. Tests MUST verify structure and relationships without duplicating unrelated mutable literals.

Evidence:

CIR-013 - Automation is scoped to a Python library

Contract: CI and release automation MUST build distributable products only as the standard pure Python wheel and source distribution. It MUST NOT contain standalone application, native executable, application-container, Node application, or Rust build processes. A local test-only SSH server image MAY be built by the owning acceptance Make target, MUST NOT be published, and MUST remain outside Python distributions. Quality, tests, distributions, and OpenSSH acceptance MUST each have one workflow owner, and publication MUST not rebuild CI artifacts.

Evidence:

CIR-014 - Local and CI container validation share one Make boundary

Contract: Local and hosted workflow validation MUST invoke the same make validate-actions contract, also included by make policy and make ci. The container engine subprocess MUST receive neither DBUS_SESSION_BUS_ADDRESS nor DBUS_SYSTEM_BUS_ADDRESS from the caller, so private application buses cannot redirect access to host services. XDG_RUNTIME_DIR and the caller's environment MUST remain intact. Native cgroup and event backends MUST NOT be replaced to mask a failure. The target MUST retain its immutable image, network isolation, read-only root and repository mount, dropped capabilities, and no-new-privileges policy, and MUST propagate engine failure without retrying under weaker settings. Ad-hoc engine overrides and direct tool commands MUST NOT substitute for passing the maintained Make targets. The acceptance image build and all acceptance engine operations MUST apply the same D-Bus-only environment cleanup without altering native client prompt routing or selecting alternate engine backends. Both live gates MUST prepare their server through make acceptance-image; make ci MUST include ordinary container-backed acceptance exactly once and MUST exclude hardware interaction. Live networking MUST be selected from engine metadata by the shared fixture: direct pasta for rootless Podman, native bridge for Docker. This selection MUST NOT depend on whether the caller is CI or local, or on the engine's executable filename. No network or AppArmor fallback MAY mask teardown errors. The optional Make setting ACCEPTANCE_DEBUG=1 MAY add engine debug logging and bounded stderr output only; it MUST NOT alter network or security arguments.

Evidence: