Skip to content

Continuous Integration And Release Contract

Assertions

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

Contract: The repository MUST contain only the reviewed CI, dependency-submission, Pages, PR-body, and release workflows. 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 behavior.

Evidence:

CIR-002 - Quality, compatibility, and distribution remain visible gates

Contract: Reusable CI MUST run the complete Linux quality contract through make ci, separately test every runtime and platform in the supported CI matrix, run Linux installer tests, run the complete live protocol suite on Linux AMD64 against the checksum-verified ephemeral Joplin Desktop build owned by the live-test runtime, and build and smoke each supported native distribution. Coverage MUST remain blocking at the reviewed floor. The live job MUST NOT use a repository credential or a pre-existing Joplin process or profile.

Evidence:

CIR-003 - Write permissions are confined to dedicated jobs

Contract: Default workflow permission MUST be read-only contents. Only the CodeQL job MAY receive security-events: write, dependency submission MAY receive job-scoped contents: write, Pages deployment MAY receive job-scoped Pages and OIDC writes, PR-body automation MAY receive pull-request write, and GitHub release publication MAY receive job-scoped contents write. PyPI publication MAY receive only job-scoped OIDC write and MUST NOT receive a stored credential.

Evidence:

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

Contract: PR-body automation MUST be the sole pull_request_target boundary, execute only trusted default-branch code, read a bounded head changelog through the API as inert data, preserve manual body content, and reject missing or oversized managed release content.

Evidence:

CIR-005 - Release version has one human-maintained owner

Contract: Root .version MUST be canonical stable SemVer and the only human-maintained version. Package metadata MUST read it dynamically and the agent manifest MUST match. A release-bearing change MUST increase the exact base version and provide a matching non-empty dated changelog section.

Evidence:

CIR-006 - Publication reuses gated artifacts and never rewrites conflict

Contract: A not-yet-published version on main MUST pass reusable CI before its Python distributions are reproducibly built once, install-smoked, and its publication jobs run. The GitHub publish job MUST create or resume an exact draft Release, combine the shared Python distributions with the smoke-tested platform artifacts, verify the full inventory and checksums, upload each exact asset through GitHub's release upload endpoint with response verification, and publish. Matching publication MUST be a read-only no-op; conflicting tags, targets, metadata, or assets MUST fail without moving or replacing history.

Evidence:

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

Contract: Dependency submission MUST trigger only on direct main push, build four validated lock manifests offline, validate the expected repository and payload shape, and submit with only its job-scoped standard token. Pull requests and reusable release invocation MUST not enter this write boundary.

Evidence:

CIR-008 - Documentation changes build before merge and publish a sitemap

Contract: Documentation, theme, hook, and docs dependency changes MUST trigger a strict non-deploying Pages build on pull requests. Direct main pushes MUST build the same content, require non-empty sitemap XML and gzip outputs, audit generated routes, links, anchors, canonical URLs, assets, and the allow-all robots.txt sitemap directive, publish the canonical domain root files, and grant deployment writes only to the deploy job.

Evidence:

CIR-009 - Contract evidence is machine-checked

Contract: Contract files MUST be the only normative documentation, use unique stable IDs and the catalogued assertion shape, and link every assertion to at least one existing test definition. The user, maintenance, and site-only trees MUST remain structurally separate and all published internal links MUST resolve in a strict MkDocs build.

Evidence:

CIR-010 - Repository ownership is explicit

Contract: .github/CODEOWNERS MUST assign every repository path to @kogeler, so the default-branch ruleset's required code-owner review applies to every pull-request change.

Evidence:

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

Contract: Release state MUST independently inspect the exact current version in PyPI and GitHub Releases. A missing PyPI version MUST publish only the gated wheel and sdist through the pypi GitHub Environment, PyPI Trusted Publishing, a job-scoped OIDC token, and the SHA-pinned official PyPA action; stored credentials and blind duplicate skipping are forbidden. GitHub MUST receive the same workflow artifact only after PyPI succeeds. If PyPI already contains the version while GitHub publication still needs recovery, the local file names, sizes, and SHA-256 digests MUST exactly match PyPI before GitHub publication continues.

Evidence:

CIR-012 - Mutable pins have one executable owner

Contract: Concrete project, dependency, runtime, protocol, schema, external-tool, action commit, and checksum values MUST be owned by the executable configuration that consumes them. Tests MUST NOT compare behavior or repository configuration with duplicated concrete version literals. They MUST instead use the owning production constant, derive expectations from synthetic inputs, or verify version-independent structure and relationships. CI version increment and release consistency enforcement MUST remain blocking.

Evidence: