Files
parity-lib/CHANGELOG.md
T
Oleks 79f9a2dd62 feat(parity): gate-ready pipeline-doctor + OCI verify-digest + stage/push-staged audit
pipeline-doctor (#191/#193): add --strict (fail on WARN) so a .woodpecker.yaml
step or pre-receive hook can gate on exit code; add documented ci/local.sh
escape-hatch (#196); fix false-negative — token/dev-tag/dry-run/meta contracts
are guaranteed by parity-lib for a consumer, so consumers PASS by delegation
instead of being penalized for not re-implementing them inline. Self-check and
numpy-s390x both pass 9/9.

mkNix2ContainerPublish (#195): add verify-digest app that builds each local arch
image and prints its OCI manifest digest (no registry contact), formalizing the
content-addressed manifest digest as the parity contract. reproducible=false is
kept deliberately (non-reproducible layer deps); digest-as-contract is the
low-risk path. Generalized from claude-plugin-registry 55f2d0b.

stage/push-staged audit (#194): verified all 8 builders expose stage-<arch> +
push-staged; all already complete, no gaps.
2026-06-02 21:11:49 +03:00

6.3 KiB

Changelog

All notable changes to parity-lib are documented here. This project follows semantic versioning; the version is a conceptual tag (no git tag is created).

Unreleased

  • Feature: verify-digest for nix2container (cluster #195). mkNix2ContainerPublish now also returns a verify-digest app that builds each locally-buildable arch image and prints its OCI manifest digest with NO registry contact (it copyTos a throwaway local oci: dir and reads the digest skopeo derives). This formalizes the manifest digest as the parity contract: the OCI layers are built reproducible = false ON PURPOSE (the fix for the "Digest did not match" caused by non-reproducible layer deps + nix2container's lazy tar regeneration), so byte-identical-tar parity is NOT promised — but the content-addressed manifest digest the registry stores the image under IS stable. Identical local vs CI digest ⇒ identical registry artifact. We do NOT flip reproducible to true (the inputs are not reproducible); the LOW-RISK digest-as-contract path was chosen instead. Generalized from the claude-plugin-registry prototype (55f2d0b) so every nix2container consumer gets it for free.
  • pipeline-doctor is now GATE-READY (cluster #191/#193). It already exited non-zero on any failing required check; added a --strict mode that ALSO fails on any WARN, so a .woodpecker.yaml step or a server pre-receive hook can call pipeline-doctor --strict <repo> and rely on the exit code. Added a documented ci/local.sh escape-hatch (cluster #196): a repo that must keep a hand-written Dockerfile/BuildKit pipeline may opt out of the archetype / parity-lib asserts (downgraded to warnings) if it ships a ci/local.sh local==CI entrypoint. Fixed a false-negative: the token / dev-tag / dry-run / meta.description contracts are GUARANTEED by parity-lib for a consumer (they live in the generated apps, not the consumer's flake.nix text), so a repo that consumes parity-lib now PASSES those by delegation instead of being penalized for not re-implementing them inline. Self-check stays green and a known-good consumer (numpy-s390x) now passes 9/9.
  • Audit: stage + push-staged uniform across all 8 builders (cluster #194). Verified every archetype builder exposes a stage-<arch> (build-parity, no registry contact, writes ./.parity-stage) AND a push-staged (replay the staged artifact): mkPyPiWheelPublish, mkPyPiWheelPublishMulti, mkS390xNpmPublish, mkS390xNpmPublishMulti, mkGenericBinaryPublish, mkGoBinaryPublish (alias), mkNix2ContainerPublish and mkHelmPublish (stage-chart). All were already complete — no gaps to fill; the build-parity / publish-parity split is uniform.
  • Feature: mkS390xNpmPublishMulti (cluster #192). A multi-version npm builder mirroring the PyPI multi one: publishes a fixed list of { version; file; distTag? } per tag, each staged into its own dir and npm published with its dist-tag (idempotent — "already exists" == success). file may be a .node addon OR a plain binary, and packageJson (with a $VERSION the stage heredoc expands) declares the shape (main vs bin), so it covers both nextjs-swc (16.1.6 @latest + 15.2.0 @next15) and sentry-cli (a binary published as an npm package at two versions). Shared parity_npm_publish_dir helper added to ci/parity-lib.sh.
  • Feature: mkPyPiWheelPublishMulti (cluster #197). A multi-version PyPI builder that publishes a fixed list of { version; wheel; } per tag instead of just the default — the pre-parity behaviour several *-s390x repos rely on. Each wheel's real version is read from its filename (PEP 427), so stage/publish/push-staged need no side-channel map and a re-run is idempotent (409-skip per version). Shared parity_pypi_post / parity_wheel_version helpers added to ci/parity-lib.sh. First consumer: numpy-s390x (5 versions).
  • Fix (safety): dev-tag guard was ineffective. Every publish app body runs VERSION="$(parity_derive_version <default>)" before parity_devtag_guard, so by the time the guard checked $VERSION it was always non-empty (the derived default) and an accidental local --publish with no explicit version and no v* tag still pushed (cluster #194 finding). The guard now reads a source-time snapshot PARITY_VERSION_EXPLICIT captured before any clobber, so it correctly blocks unless the caller set $VERSION or $CI_COMMIT_TAG matches ^v[0-9].
  • pipeline-doctor (cluster #191 security sweep): added a scoped per-file check asserting no set -x in token-bearing ci/*.sh scripts going forward — a script that references a registry token (REGISTRY_TOKEN / CI_REGISTRY_TOKEN / an Authorization: token header) must not enable xtrace, which would echo the token to the build log. Token-free helpers (e.g. version parsers) are not flagged.

v0.1.0

Initial release (cluster #192/#193/#194, emmett#44).

  • lib.mkParityBuilders pkgs plus per-builder wrappers exposing the six archetype publish-app builders:
    • mkPyPiWheelPublish — single-arch Gitea PyPI wheel.
    • mkS390xNpmPublish — single-arch Gitea npm native addon.
    • mkGenericBinaryPublish — single-arch Gitea generic-registry binary.
    • mkGoBinaryPublish — alias of mkGenericBinaryPublish (explicit archetype).
    • mkNix2ContainerPublish — multi-arch OCI image with publish-index and :latest digest copy.
    • mkHelmPublish — Helm chart to an OCI registry.
  • Each builder returns flake apps following the corrected parity standard: stage-<arch> (build-parity, no registry), publish-<arch> (dry-run by default), publish-index (build-free, fail-closed multi-arch assembly via regctl), publish (all local arches + index + :latest last), and push-staged (replay ./.parity-stage).
  • Shared shell library ci/parity-lib.sh (token resolution with $REGISTRY_TOKEN + pass fallback and never printed, dev-tag guard, version derivation, the dry-run gate, registry preflight, stage-dir helpers).
  • packages.pipeline-doctor / apps.pipeline-doctor (cluster #193): static parity-contract checker that prints local-equivalent commands.
  • flake.lock fully pinned; nixpkgs follows the shared fleet-pins nixpkgs-ci.