413f78c365
Branch-deploy repos (event: push + branch:, tagging each push from CI_COMMIT_*/pipeline-number) are a deliberate continuous-deploy guard, not the absence of one. cms-plugins/emdash/kotkanagrilli -> 9/9; trio + self-test unchanged; a tagless default-version publish still FAILs.
10 KiB
10 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
- Fix:
pipeline-doctormodels branch-deploy repos (#204). The dev-tag-guard check only accepted arefs/tags/v*tag gate, so web-app/CMS repos that deploy on a branch push (event: push+branch: develop/staging/production) and tag each push fromCI_COMMIT_BRANCH/CI_COMMIT_SHA/CI_PIPELINE_NUMBER(a deterministic per-push tag, no default-version clobber) false-failed. The check now accepts that branch-deploy form as a valid guard. cms-plugins, emdash-kotkanagrilli, kotkanagrilli.fi → 9/9; trio + self-test unchanged; a taglessevent: pushpublish with NO per-push tag still FAILs. - Fix:
pipeline-doctornow reads a.woodpecker/DIRECTORY (#202). It only folded the single-file.woodpecker.yaml/.ymlintoci_txt; repos whose Woodpecker config is a.woodpecker/directory (per-arch workflows) had theirrefs/tags/v*trigger invisible, so the dev-tag-guard check false-failed. Now globs.woodpecker/*.yaml|*.ymltoo. Effect: commonground-legacy + csi-s3 go 9/9. (cms-plugins still 8/9 — but legitimately: it's a branch-deploy repo with nov*tag at all, a separate heuristic gap tracked elsewhere.) - Fix:
pipeline-doctortoken-heuristic false positives (#199). The audit sweep wrongly FAILED ~9 correctly-converted ci-script repos on two heuristics. (1) The token-contract check only accepted a hard-codedpass <literal-path>; it now also accepts the secure indirectionpass "$PASS_ENTRY"/pass "$VAR"(a quoted/unquoted shell var, optionally viapass show). (2) The leak scan flagged the blessedecho "$TOKEN" | docker login … --password-stdin(and--pass-stdin, and helmregistry login) idiom — the token goes to STDIN, not the log — because the--password-stdinflag often sits on a\-wrapped continuation line the line-based grep never saw on theecholine. The scan now flattens\-continuations and folds the pipe target onto theecholine, then exempts the… | <cmd> … --password-stdin/--pass-stdinfeed. Real leaks still FAIL: a bareecho "$TOKEN"to stdout or a file, andset -xin a token script. Added--self-test: six inline fixtures lock in both fixes and the three must-still-catch leaks. Verified: version-radar, xonsh, common-chronicle, ii-researcher, ironclaw, openclaw now PASS; parity-lib--strict ., gitea-mcp, numpy-s390x still 9/9. (commonground-legacy / cms-plugins / csi-s3 still FAIL one UNRELATED check — dev-tag-guard — because their woodpecker config lives in a.woodpecker/directory the doctor doesn't yet read; out of scope for #199.) - Feature:
mkAtticClosurePublish— the attic-closure builder (cluster #198). Models the archetype parity-lib was missing: build a Nix closure and push it to the Attic binary cache (NO registry artifact). Yieldsstage-<arch>(nix buildthe closure, no push),publish-<arch>/publish(build +attic login+attic push; dry-run by default,--publish/PUBLISH=1to push; token via$ATTIC_TOKENorpass, never echoed), andpush-staged. Lets caddy-with-replace (#104) drop its generic-publish over-reach and overlay-xonsh (#105) convert off N/A; flake-hub / woodpecker-peek can retire their bespoke attic wraps. pipeline-doctornon-flake mode (cluster #191/#193). A repo with NO rootflake.nixis now a VALID parity form if it ships the ci-script entrypoints (ci/local.sh, orci/build.sh+ci/publish.sh) called by a thin.woodpecker.yaml— so the non-flake go-binary/helm references (gitea-mcp, helms) PASS the gate instead of failing for lacking a flake. The token-leak scan and the #191 no-set -x-in-token-scripts scan still run on theirci/*.shin full. Verified: gitea-mcp now 9/9, parity-lib + numpy-s390x still 9/9.- Feature:
verify-digestfor nix2container (cluster #195).mkNix2ContainerPublishnow also returns averify-digestapp that builds each locally-buildable arch image and prints its OCI manifest digest with NO registry contact (itcopyTos a throwaway localoci:dir and reads the digest skopeo derives). This formalizes the manifest digest as the parity contract: the OCI layers are builtreproducible = falseON 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 flipreproducibletotrue(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-doctoris now GATE-READY (cluster #191/#193). It already exited non-zero on any failing required check; added a--strictmode that ALSO fails on anyWARN, so a.woodpecker.yamlstep or a server pre-receive hook can callpipeline-doctor --strict <repo>and rely on the exit code. Added a documentedci/local.shescape-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 aci/local.shlocal==CI entrypoint. Fixed a false-negative: the token / dev-tag / dry-run /meta.descriptioncontracts are GUARANTEED by parity-lib for a consumer (they live in the generated apps, not the consumer'sflake.nixtext), 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 apush-staged(replay the staged artifact):mkPyPiWheelPublish,mkPyPiWheelPublishMulti,mkS390xNpmPublish,mkS390xNpmPublishMulti,mkGenericBinaryPublish,mkGoBinaryPublish(alias),mkNix2ContainerPublishandmkHelmPublish(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 andnpm published with its dist-tag (idempotent — "already exists" == success).filemay be a.nodeaddon OR a plain binary, andpackageJson(with a$VERSIONthe stage heredoc expands) declares the shape (mainvsbin), 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). Sharedparity_npm_publish_dirhelper added toci/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*-s390xrepos 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). Sharedparity_pypi_post/parity_wheel_versionhelpers added toci/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>)"beforeparity_devtag_guard, so by the time the guard checked$VERSIONit was always non-empty (the derived default) and an accidental local--publishwith no explicit version and nov*tag still pushed (cluster #194 finding). The guard now reads a source-time snapshotPARITY_VERSION_EXPLICITcaptured before any clobber, so it correctly blocks unless the caller set$VERSIONor$CI_COMMIT_TAGmatches^v[0-9]. pipeline-doctor(cluster #191 security sweep): added a scoped per-file check asserting noset -xin token-bearingci/*.shscripts going forward — a script that references a registry token (REGISTRY_TOKEN/CI_REGISTRY_TOKEN/ anAuthorization: tokenheader) 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 pkgsplus 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 ofmkGenericBinaryPublish(explicit archetype).mkNix2ContainerPublish— multi-arch OCI image withpublish-indexand:latestdigest 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 +:latestlast), andpush-staged(replay./.parity-stage). - Shared shell library
ci/parity-lib.sh(token resolution with$REGISTRY_TOKEN+passfallback 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.lockfully pinned; nixpkgs follows the sharedfleet-pinsnixpkgs-ci.