466 lines
28 KiB
Markdown
466 lines
28 KiB
Markdown
# Package Registry Releases
|
|
|
|
GovOPlaN publishes reusable module artifacts through Gitea's native PyPI and
|
|
npm registries. These packages improve developer installation, release
|
|
resolution, cacheability, and artifact inspection. They do not replace the
|
|
signed runtime distribution: the signed manifest and digest-pinned OCI images
|
|
remain the production deployment authority.
|
|
|
|
## Publication boundary
|
|
|
|
Every repository with a `pyproject.toml` contains
|
|
`.gitea/workflows/module-package-release.yml`. The meta repository owns the
|
|
canonical template and installs it with:
|
|
|
|
```bash
|
|
python tools/repo/sync-module-package-workflows.py --write
|
|
python tools/repo/sync-module-package-workflows.py --check
|
|
```
|
|
|
|
The workflow runs for `v*` tags and may be dispatched manually for an existing
|
|
tag. The organization preflight verifies that every package repository protects
|
|
the `v*` namespace. Before building, the workflow itself verifies that:
|
|
|
|
- the tagged commit is contained in `main`;
|
|
- the tag, Python project version, and optional WebUI package version agree;
|
|
- package names remain in the `govoplan-*` and `@govoplan/*-webui` namespaces.
|
|
|
|
The workflow binds the repository explicitly from the Gitea Actions context.
|
|
Do not rely on GitHub-compatible environment variables being injected by the
|
|
runner image; Gitea runners may expose only the context values. Gitea 1.24 job
|
|
tokens cannot read repository tag-protection settings, so package jobs must not
|
|
receive a broad administrator token merely to repeat the organization preflight.
|
|
Run the following before the first publication and after repository or tag-rule
|
|
changes:
|
|
|
|
```bash
|
|
python tools/gitea/gitea-configure-package-releases.py
|
|
```
|
|
|
|
Preview and dispatch the exact wheel/WebUI versions selected by the developer
|
|
meta-package with:
|
|
|
|
```bash
|
|
python tools/gitea/gitea-dispatch-package-set.py \
|
|
--env-file ~/.config/gitea/gitea.env
|
|
python tools/gitea/gitea-dispatch-package-set.py \
|
|
--env-file ~/.config/gitea/gitea.env \
|
|
--apply
|
|
```
|
|
|
|
The dispatcher reads exact versions from `packages/govoplan-meta/pyproject.toml`,
|
|
inspects the selected tag to determine whether a WebUI package is expected,
|
|
skips complete registry pairs and does not duplicate an active workflow. Use
|
|
`--repository govoplan-core` for a bounded dispatch or `--verify-existing` to
|
|
rebuild and hash-verify versions already present in both registries.
|
|
|
|
For coordinated lockstep tags, `push-release-tag.sh` pushes module tags first,
|
|
Core next, and the meta tag last. This is a dependency guarantee for a
|
|
single-capacity Actions runner: the developer package cannot run before its
|
|
exact Core and module versions have entered the queue.
|
|
|
|
The same release entry point first validates the migration graph, then records
|
|
the reviewed current Alembic heads under the target release version and reruns
|
|
the strict migration audit before it changes package versions, commits, or
|
|
tags. The default preflight intentionally does not require those heads to exist
|
|
in the previous release baseline. A failed candidate-baseline check therefore
|
|
cannot produce a protected package release.
|
|
|
|
The source gate validates `pyproject.toml`, the module version declaration
|
|
(`MODULE_VERSION` or the top-level `ModuleManifest.version`), public package
|
|
`__version__`, and WebUI metadata before creating tags. Release-tag artifact
|
|
checks run only after the candidate tags and immutable WebUI lock have been
|
|
created locally.
|
|
|
|
Release-lock regeneration resolves a fresh immutable lock from the reviewed
|
|
candidate manifests; it does not seed resolution from the previous release
|
|
lock. This prevents removed transitive packages and stale peer metadata from
|
|
blocking or contaminating the new release. Candidate resolution also uses an
|
|
isolated temporary npm cache, so a locally replaced tag cannot reuse metadata
|
|
from a failed, unpushed release attempt.
|
|
|
|
Modules that retain the same WebUI package identity in both a root publish
|
|
manifest and `webui/package.json` use the WebUI manifest as the canonical peer
|
|
contract. The coordinated release synchronizes `peerDependencies` and
|
|
`peerDependenciesMeta` into the publish manifest before creating the module
|
|
tag, then synchronizes each lockfile root from the final package metadata. A
|
|
distinct root package remains independent.
|
|
|
|
Every module referenced by Core's Git-based `package.release.json` must expose
|
|
its WebUI identity at the repository root, including matching peer requirements
|
|
and `webui/`-prefixed entry exports (also CSS subpaths). npm resolves Git
|
|
dependencies from the repository root, while the native-package workflow packs
|
|
`webui/`; success in one path does not verify the other. Run
|
|
`python tools/checks/check-webui-package-facades.py` after changing either
|
|
manifest or the release composition. The focused gate also runs this check.
|
|
Adding or correcting a facade in an already published repository requires a
|
|
new patch tag; never repair an existing immutable tag in place.
|
|
|
|
It builds one wheel and, where applicable, one npm tarball. The workflow records
|
|
the source tag, source commit, filename, size, and SHA-256 in
|
|
`package-artifacts.json` before publishing. Gitea rejects a second upload of the
|
|
same package version, so correction requires a new version rather than artifact
|
|
replacement.
|
|
|
|
A retry after partial publication is safe. Before upload, the workflow reads the
|
|
native package registry file record and compares its SHA-256 with the artifact
|
|
rebuilt from the protected tag. An exact existing artifact is skipped; a
|
|
same-version artifact with another digest or an unexpected file set fails
|
|
closed. This permits a failed npm publication to resume without weakening
|
|
package immutability or accepting `--skip-existing` blindly.
|
|
|
|
The npm tarball is always published through an explicit local `./dist/...`
|
|
path. Without that prefix, npm may interpret a relative tarball name as a Git
|
|
package shorthand before it ever contacts the configured registry.
|
|
|
|
Published WebUI packages contain registry-compatible dependencies only. The
|
|
workflow converts an internal dependency pinned to a protected `vX.Y.Z` Git tag
|
|
into the exact `X.Y.Z` registry version and rejects unresolved `file:` or Git
|
|
dependencies. Repository development metadata may therefore keep local or Git
|
|
references without leaking them into the published package contract.
|
|
Historical `add-ideas` and current `GovOPlaN` organization URLs are accepted
|
|
for immutable tagged releases; both normalize to the same exact registry
|
|
dependency and no branch or unversioned Git reference is accepted.
|
|
|
|
## One-time Gitea setup
|
|
|
|
Protect `v*` tags in every package repository and the meta repository. Allow
|
|
only the `Owners` team to create or delete those tags.
|
|
|
|
```bash
|
|
set -a
|
|
. ~/.config/gitea/gitea.env
|
|
set +a
|
|
python tools/gitea/gitea-configure-package-releases.py --apply
|
|
```
|
|
|
|
Create a dedicated personal access token with only `write:package` scope and
|
|
store these organization-level Actions secrets on `GovOPlaN`:
|
|
|
|
- `GOVOPLAN_PACKAGE_USERNAME`: account owning the package token;
|
|
- `GOVOPLAN_PACKAGE_TOKEN`: dedicated package-write token.
|
|
|
|
Do not use an administrator or general release token. Gitea 1.24 does not grant
|
|
package publication to the automatic Actions job token. Organization secrets
|
|
allow the same least-privilege credential to serve every module workflow.
|
|
|
|
## Exact release consumption
|
|
|
|
`tools/release/generate-release-package-set.py` supports two explicit package
|
|
profiles. `base` translates the reviewed roots in `requirements-release.txt`;
|
|
`full` reads the exact `govoplan[full]` dependency set from the developer
|
|
meta-package. Both profiles resolve every version tag to its commit and verify
|
|
the package metadata from that exact Git tree. The official module directory
|
|
and immutable runtime distribution use `full`, so every publicly released
|
|
module can be discovered without rebuilding the application image.
|
|
|
|
`tools/release/resolve-package-artifacts.py` then downloads exactly those wheel
|
|
and WebUI versions from Gitea. It reads the identity embedded in every wheel and
|
|
npm tarball, rejects missing, duplicate, unexpected, or oversized artifacts,
|
|
and writes `package-artifacts.lock.json` with credential-free HTTPS download
|
|
URLs, SHA-256 values, and npm registry integrity values. The resolver verifies
|
|
that the bytes downloaded by `npm pack` match the registry's own integrity
|
|
record. Credentials are accepted only through environment variables and are
|
|
never written to the lock. Python resolution ignores ambient pip configuration
|
|
and extra indexes for GovOPlaN roots, preventing an internal package name from
|
|
being selected from an undeclared registry.
|
|
|
|
The runtime distribution workflow uses the verified full-profile wheelhouse
|
|
directly and installs every selected module WebUI tarball only after matching
|
|
it to the lock. It publishes the package set, package lock, and hash-locked
|
|
requirements as release assets.
|
|
The WebUI installer receives the absolute runtime-build interpreter path so its
|
|
directory changes cannot escape the isolated release environment.
|
|
Gitea 1.24 dispatches this workflow from a branch, but that branch is only the
|
|
workflow implementation. The job fetches and peels the protected `v<version>`
|
|
tag explicitly and materializes both `requirements-release.txt` and the
|
|
developer meta-package from that Git tree. It then binds the signed distribution
|
|
source and Gitea release assets to the same exact commit. A post-tag workflow
|
|
repair can therefore retry publication without changing the released package
|
|
composition or relabelling the later branch commit as released source.
|
|
The package-lock SHA-256 is part of the signed distribution manifest. Runtime
|
|
finalization also requires the lock's package versions and hashes to match the
|
|
wheel composition embedded in the images. OCI assembly remains network-free
|
|
after package and third-party dependency resolution.
|
|
|
|
The source refs remain in the module catalog for source provenance and release
|
|
planning. Production installation consumes the signed runtime images rather
|
|
than invoking `pip`, `npm`, or Git on the target host.
|
|
|
|
## Public module directory
|
|
|
|
For an operator-reviewed full publication, use
|
|
`tools/release/release-catalog.py full-registry` followed by the same tool's
|
|
`publish-candidate` command. Resolve the package set and registry lock first;
|
|
the older direct-write shell wrapper is not the strict candidate publication
|
|
path. See [Full registry candidates / Vollständige Registry-Kandidaten](FULL_REGISTRY_CANDIDATES.md)
|
|
for the private host runtime, exact artifact checks, and legacy keyring transition.
|
|
Catalog entries are synthesized from
|
|
the exact tagged module manifests, never from a hand-maintained module list or
|
|
the current workspace. Each entry binds its Python wheel and optional WebUI
|
|
tarball to the registry URL, filename, size, SHA-256, package identity, source
|
|
tag, and source commit before the complete catalog is signed.
|
|
|
|
The same publication transaction regenerates and prunes the browsable static
|
|
directory under `public/catalogs/v1/modules/`. It writes a global
|
|
`modules/index.json`, one `<module>/index.json`, and one
|
|
`<module>/<version>/manifest.json` for every entry in the signed channel.
|
|
These files are derived from that exact signed payload and keyring; stale JSON
|
|
from an older partial catalog is removed while unrelated static assets are left
|
|
untouched. The signed channel remains the trust anchor, while the module
|
|
directory provides stable discovery URLs for browsers and external tooling.
|
|
|
|
Official GovOPlaN modules are open-source directory entries and do not require
|
|
license entitlements. The generic `license_features` contract remains available
|
|
for third-party package directories, support/configuration packages, or future
|
|
deployment-specific presets. A catalog entry is gated only when that entry
|
|
explicitly declares such features.
|
|
|
|
Core carries the public stable catalog URL and its independently pinned trust
|
|
anchor. In the absence of an operator-configured catalog, Admin discovers the
|
|
official directory automatically. Selecting an entry creates a reviewed
|
|
install/update plan; the trusted installer downloads the exact signed artifacts
|
|
into a private digest cache, verifies size and hash, and installs only from that
|
|
cache. A saved plan is rejected if any package ref, artifact identity, catalog
|
|
channel, sequence, or signing-key identity differs from the currently validated
|
|
catalog.
|
|
|
|
The Admin directory can be searched by module, package, repository, or tag and
|
|
filtered by available, installed, update, and blocked/withdrawn states. It
|
|
shows the source revision, artifact digest, release notes, and configuration
|
|
requirements. Missing dependency/interface providers and unsupported update
|
|
windows are surfaced before an operator adds the entry to a plan; installer
|
|
preflight remains authoritative.
|
|
|
|
Catalog entries also carry the permission definitions declared by the tagged
|
|
module manifest. Admin groups and exposes their scopes before an install or
|
|
update is planned. This is disclosure only: installing a module does not grant
|
|
its permissions to an account, role, group, tenant, or service account.
|
|
|
|
Package lifecycle and availability are intentionally separate:
|
|
|
|
- install, update, and uninstall change the instance-wide package composition;
|
|
- enable and disable change the active instance runtime graph;
|
|
- tenant module entitlements define unavailable, available, and forced modules;
|
|
- group/user presentation is governed through Views and Policy; and
|
|
- enabling a capability module does not opt data into that capability.
|
|
|
|
Single-process or single-host installations may execute a supervised package
|
|
plan locally. Shared-state and Kubernetes profiles reject node-local package
|
|
mutation: operators compose and roll out a new signed full-profile runtime image
|
|
instead. This prevents replicas from drifting while retaining the same Admin
|
|
catalog and preflight experience.
|
|
|
|
## Developer meta-package
|
|
|
|
`packages/govoplan-meta` builds the optional `govoplan` package. Its default
|
|
dependencies mirror the reviewed runtime roots; `govoplan[full]` adds all
|
|
currently packageable workspace modules. Regenerate it after changing release
|
|
requirements or package versions:
|
|
|
|
```bash
|
|
python tools/release/generate-developer-meta-package.py
|
|
python tools/release/generate-developer-meta-package.py --check
|
|
```
|
|
|
|
The direct generator is a development synchronization tool, not a receipt-gated
|
|
release executor. For release preparation, use the guarded out-of-run stage below.
|
|
|
|
`push-release-tag.sh` performs this synchronization before release commits and
|
|
tags. The meta-package is for editable/developer setup and composition tests. It
|
|
does not enable modules, apply migrations, provision services, or establish
|
|
backup and recovery evidence.
|
|
|
|
### Shared source-tag contract and Meta composition
|
|
|
|
The shared version collector names Meta's real
|
|
`packages/govoplan-meta/pyproject.toml` separately from root `pyproject.toml`.
|
|
Only the registered `govoplan` system/meta repository with nested project name
|
|
`govoplan` receives this contract. Missing, unknown, or misidentified metadata
|
|
does not become a versionless exception. Version alignment compares the complete
|
|
nested file with the canonical operator-tool generator output: its version must
|
|
match Core, and dependencies and `full` composition must match the reviewed
|
|
requirements and workspace package versions. Validation never executes a
|
|
generator from a selected checkout. The shared trusted manifest checker can
|
|
load reviewed application manifests; these checks are not a code sandbox.
|
|
|
|
Meta's complete generated file is recognized by shared version-mutation discovery,
|
|
but the generic durable version executor deliberately cannot write it. A durable
|
|
run freezes the release console's own Meta checkout as trusted runtime code;
|
|
changing it in place would invalidate that run. The planner therefore places Meta
|
|
after Core and exposes only non-executable support preparation/publication steps,
|
|
not misleading automatic Meta version, commit, tag, or push actions. A missing or
|
|
different Core target produces an actionable preparation prerequisite.
|
|
|
|
Prepare Core and the intended module inputs first, commit their reviewed state,
|
|
then stop active durable runs for the target workspace. Use trusted operator tools
|
|
against a separate registered, private source checkout, never the running operator
|
|
Meta directory. Preview outside any selected source checkout, for example:
|
|
|
|
```sh
|
|
python tools/release/prepare-developer-meta-package.py \
|
|
--workspace /private/release-workspace --target-version X.Y.Z \
|
|
> /private/operator/meta-preview.json
|
|
python tools/release/prepare-developer-meta-package.py \
|
|
--workspace /private/release-workspace --target-version X.Y.Z \
|
|
--receipt /private/operator/meta-preview.json --apply --confirm-out-of-run
|
|
```
|
|
|
|
The explicit confirmation attests that no durable run is active for that target
|
|
workspace; the helper does not discover or stop other processes. Preview/apply
|
|
requires registered clean main sources, matching origins and live-main ancestry,
|
|
Core already aligned at the target, the exact nested identity, and no existing or
|
|
unverifiable target Meta tag. Frozen receipts cover source HEADs/filesystem
|
|
identities, release requirements, every discovered registered full-composition
|
|
pyproject, the trusted generator snapshot, and the resulting full-file hash.
|
|
Inputs are limited to 128 selected files, 2 MiB per file and 16 MiB aggregate.
|
|
The canonical generator renders copied bounded data in a temporary directory;
|
|
no generator from the selected checkout executes. Changed receipts block before
|
|
the file effect. Apply writes only `packages/govoplan-meta/pyproject.toml`, then
|
|
rechecks the other sources and exact output. A write or post-check failure that
|
|
may have changed the file reports `needs-reconciliation` and leaves that bounded
|
|
delta for explicit review; it never retries, rolls back, commits or publishes.
|
|
|
|
Review the complete generated composition and manually commit the resulting file.
|
|
Complete matching Core publication before guarded Meta source tagging/publication,
|
|
then start a fresh durable run from reviewed, clean, published operator tooling.
|
|
Hot self-updating durable Meta release execution remains explicitly unsupported;
|
|
this out-of-run preparation is the existing developer-meta support contract.
|
|
|
|
For every `tag_repositories` batch, strict checks apply to every selected
|
|
repository before any tag creation, fetch, or push: registered checkout and
|
|
origin/push URL, a clean `main` tracking `origin/main`, live remote-main ancestry,
|
|
exact frozen HEADs, and immutable annotated local/remote tag objects. Git metadata
|
|
must remain inside the operator's trusted workspace. Missing local knowledge of
|
|
live remote main is a blocker; fetch and review it separately. Unknown repositories
|
|
and non-registered remote aliases fail closed. If selected, Meta runs last.
|
|
For Meta only, the matching annotated Core release must exist before its effect; Core may be
|
|
an earlier selected repository, or an already tagged dependency. Publication
|
|
requires that Core's exact tag and main commit are already remote.
|
|
|
|
Non-Meta selections do not acquire Meta's composition or Core-tag prerequisite.
|
|
Local module-candidate tags still work before Core's final release lock or tag.
|
|
The existing Core WebUI bundle gate still applies to module publication and
|
|
batches selecting Core: relevant Core release-package and release-lock inputs
|
|
must be operator-owned regular files, at most 16 MiB each, and their identities
|
|
and content hashes are frozen before preflight and rechecked before every effect.
|
|
When Core is unselected, this does not require its checkout to be clean or tagged;
|
|
reviewed pending composition inputs retain their previous meaning. Backend-only
|
|
selections never read irrelevant Core WebUI files.
|
|
|
|
Before even read-only Git commands, source ancestry must be owned by root or the
|
|
current operator and must not be group/world writable. A sticky shared ancestor
|
|
such as `/tmp` is permitted only above an owned, protected child; the workspace
|
|
and checkouts receive no writable-directory exception. The current operator must
|
|
own source inputs and actual Git/worktree/common metadata, which must be regular
|
|
files/directories, non-symlinked, and non-writable by other users. Metadata walks
|
|
are bounded to 500,000 entries and 128 levels, and tracked inputs to 100,000 paths
|
|
and 16 MiB of listing text. Read-only Git targets, object alternates/grafts and
|
|
hidden/sparse/unmerged index entries are blocked. Frozen receipts include actual
|
|
checkout/Git directory paths, devices, inodes, owners and modes, so replacing Git
|
|
metadata with the same HEAD is still detected. All selected version/composition
|
|
inputs must be tracked, including root and WebUI package/lock metadata, discovered
|
|
module manifests and package initializers, and Meta's nested package and release
|
|
requirements; ignored working files cannot supply declarations absent from a tag.
|
|
No chmod, ownership repair or
|
|
global Git trust change is performed. A shared writable workspace must first be
|
|
recreated or reviewed in the operator's protected release area by an explicitly
|
|
authorized preparation workflow.
|
|
|
|
Preview is read-only. Local-tag mode creates only pinned annotated tags (or
|
|
retrieves an identical published annotation); it does not publish main or tags.
|
|
Publish mode atomically pushes the frozen main commit and annotation object,
|
|
without force, retagging, fallback, or automatic retry. The complete source
|
|
receipt is rechecked before every effect and afterward; remote main and the
|
|
exact annotated tag must both match, not merely the Git exit status. Changes
|
|
after preflight stop the remaining batch. Atomicity is per repository, not
|
|
across repositories: earlier successful publications and a newly created local
|
|
tag can remain after a later failure. Inspect reported receipts and obtain a new
|
|
review before retrying; do not move immutable tags.
|
|
|
|
Whole-batch revalidation deliberately repeats source and live-remote checks around
|
|
each repository effect; the number of checks can grow quadratically with batch
|
|
size. Plan release time accordingly rather than bypassing trust checks. The
|
|
shared internal preflight is read-only and exposes no legacy mutation path.
|
|
The fixture suite covers Meta and non-Meta preview/local-tag/
|
|
publication using temporary local bare remotes, including stale compositions,
|
|
unsafe origins, divergent branches, damaged tag identity, changed receipts and
|
|
false publication success. This is local tooling evidence, not a real release
|
|
publication or production permission check.
|
|
|
|
Deutsch: Die gemeinsamen Helfer erkennen ausschließlich das registrierte
|
|
Meta-Repository mit dem echten Paket `packages/govoplan-meta/pyproject.toml`
|
|
(Projektname `govoplan`). Version und vollständige Zusammensetzung müssen dem
|
|
kanonischen Generator, Core und den geprüften Anforderungen entsprechen; der
|
|
Generator stammt niemals aus dem ausgewählten Checkout. Der gemeinsame
|
|
Manifestprüfer kann geprüften Anwendungscode laden und ist keine Sandbox.
|
|
Die gemeinsame Änderungsplanung erkennt die vollständig generierte Paketdatei,
|
|
aber der dauerhafte Versionsausführer darf Meta nicht selbst verändern: sein
|
|
eingefrorener Lauf bindet den Meta-Checkout als vertrauenswürdigen Programmstand.
|
|
Meta erscheint deshalb nach Core ausschließlich mit nicht automatisch ausführbaren
|
|
Vorbereitungs-/Veröffentlichungsschritten. Zuerst Core und Modulquellen vorbereiten
|
|
und geprüft committen; bei abweichender Core-Zielversion nennt der Plan diese
|
|
Voraussetzung ausdrücklich. Aktive dauerhafte Läufe des Ziel-Workspaces beenden.
|
|
Mit `prepare-developer-meta-package.py` zunächst eine Vorschau außerhalb der
|
|
Quell-Checkouts speichern, dann deren JSON über `--receipt` zusammen mit `--apply`
|
|
und `--confirm-out-of-run` bestätigen. Das Ziel muss ein separater registrierter
|
|
privater Checkout sein, niemals das laufende Operator-Meta. Die Bestätigung ist
|
|
eine Betreibererklärung; der Helfer sucht oder beendet keine fremden Prozesse.
|
|
Quell-HEADs, Pfadidentitäten, Anforderungen, alle registrierten vollständigen
|
|
Paket-Eingaben, der vertrauenswürdige Generator und der vollständige Ausgabehash
|
|
werden eingefroren. Es gelten höchstens 128 Quelldateien, 2 MiB je Datei und
|
|
16 MiB insgesamt. Core muss bereits vollständig zur Zielversion passen; vorhandene
|
|
oder nicht verifizierbare Meta-Zieltags sperren die Vorbereitung. Geänderte
|
|
Nachweise stoppen vor dem Schreiben. Ausschließlich die verschachtelte Paketdatei
|
|
wird vollständig generiert und danach geprüft; ein Fehler nach dem Schreiben
|
|
meldet `needs-reconciliation` und erfordert die manuelle Prüfung dieser begrenzten
|
|
Änderung, ohne automatisches Zurücksetzen. Kein automatischer
|
|
Commit, Push oder Wiederholungsversuch findet statt. Zusammensetzung prüfen,
|
|
manuell committen, Core zuerst veröffentlichen, dann die geschützte Meta-Tag-Route
|
|
verwenden und einen neuen dauerhaften Lauf starten. Eine Selbstaktualisierung
|
|
des aktiven dauerhaften Meta-Laufs bleibt ausdrücklich nicht unterstützt.
|
|
Für jeden Tag-Stapel, auch ohne Meta, gelten
|
|
Vertrauens-, Origin-, saubere Main- und Live-Abstammungsprüfungen für die gesamte
|
|
Auswahl vor jeder Änderung. Unbekannte Repositories und nicht registrierte
|
|
Remote-Aliase sind gesperrt. Nur bei ausgewähltem Meta gelten zusätzlich dessen
|
|
Zusammensetzungsprüfung und der passende annotierte Core-Tag als Voraussetzung;
|
|
Meta folgt zuletzt. Für Metas Veröffentlichung müssen Core-Tag und Main-Commit
|
|
bereits auf dem Remote vorliegen. Lokale Modul-Kandidatentags bleiben vor Cores
|
|
abschließendem Release-Lock und Tag möglich. Die vorhandene Core-WebUI-Bundleprüfung
|
|
bleibt bei Modulveröffentlichung und Core-Auswahl erhalten. Relevante Core-Paket-
|
|
und Lockdateien müssen eigene reguläre Dateien mit höchstens je 16 MiB sein;
|
|
Identität und Inhaltshash werden eingefroren und vor jeder Aktion erneut geprüft.
|
|
Nicht ausgewähltes Core benötigt dafür weder einen sauberen Checkout noch einen
|
|
Tag. Reine Backend-Auswahlen lesen keine irrelevanten Core-WebUI-Dateien.
|
|
Vor Git-Aufrufen werden Eigentümer, Schreibrechte, sichere
|
|
Pfadabstammung und echte Git-/Worktree-Metadaten geprüft; veränderbare gemeinsame
|
|
Verzeichnisse, fremde Eigentümer, Alternates, Grafts und versteckte Indexeinträge
|
|
sind gesperrt. Ein Sticky-Bit-Vorfahr wie `/tmp` ist nur oberhalb eines eigenen
|
|
geschützten Unterverzeichnisses zulässig. Es erfolgen weder Rechtereparaturen
|
|
noch globale Git-Vertrauensänderungen. Ausgewählte Versions- und Zusammensetzungs-
|
|
dateien müssen versioniert sein: Paket-/Lockdateien, Modulmanifeste und
|
|
Paketinitialisierer sowie Metas verschachteltes Paket und Release-Anforderungen.
|
|
Ignorierte Arbeitsdateien dürfen keine vom Tag abweichenden Angaben liefern.
|
|
Die Vorschau schreibt nichts, lokale Tags veröffentlichen nichts,
|
|
und die Veröffentlichung überträgt Main und den exakten annotierten Tag atomar
|
|
je Repository. Unmittelbar vor und nach den Aktionen werden die eingefrorenen
|
|
Quellnachweise erneut geprüft, einschließlich entferntem Main und Tag-Objekt.
|
|
Bei Änderungen oder Fehlern stoppt der Rest des Stapels ohne automatischen
|
|
Wiederholungsversuch. Frühere Veröffentlichungen und neu erzeugte lokale Tags
|
|
können bestehen bleiben: vor einem neuen Versuch Nachweise prüfen und erneut
|
|
freigeben, niemals unveränderliche Tags verschieben. Die vollständigen Quell- und
|
|
Live-Remote-Prüfungen werden um jede Aktion wiederholt; bei großen Stapeln kann
|
|
deren Anzahl quadratisch wachsen. Diese konservativen Prüfkosten gehören zur
|
|
Release-Planung. Der interne Vorprüfer ist ausschließlich lesend und besitzt
|
|
keinen alten Änderungspfad. Tests für Auswahlen mit und ohne Meta verwenden
|
|
nur temporäre lokale Remotes und ersetzen keine echte Veröffentlichungsprüfung.
|
|
|
|
If the tag-triggered developer meta-package job fails before publication, rerun
|
|
`publish-developer-meta-package.yml` with the existing protected version. The
|
|
manual path validates that tag against `main`, checks out its exact commit, and
|
|
publishes only when the registry does not already contain the same wheel hash.
|
|
|
|
Generic Packages are intentionally not used. Add that transport only when a
|
|
consumer needs an artifact format unsupported by PyPI, npm, Gitea Releases, or
|
|
the OCI registry.
|