Skip to content

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 21:08
· 86 commits to main since this release

0.12.0 (2026-09-11)

Features

  • licence: a PEP 440 version comparator for python bounds (2ae43d2)
  • licence: composer serves only licensed versions (d85e27d)
  • licence: confirm before revoking a shared assignment, warn on bounds that exclude everything (2dbd5f6)
  • licence: manage a package's customer releases from the package page (fa92b84)
  • licence: npm serves only licensed versions, tags repointed (1df6f4b)
  • licence: one service decides which versions a licence admits (6a55b0c)
  • licence: one writer for assignment period and bounds (5cf8655)
  • licence: the pypi index respects licence bounds (b4c9d7d)
  • licence: version bounds on a package assignment (c3526a5)
  • portal: show when newer versions are outside the licence (fe34293)

Bug Fixes

  • licence: normalize semver bounds and refuse an empty version window (6c30ce2)
  • licence: one query for windowsForOrganization, fail closed on bad bounds, refuse Docker (0aec7f5)
  • licence: serve npm versions and dist-tags as objects when a licence admits none (66db52d)
  • licence: stop polling sync status for a viewer who cannot resync (b08e8bd)
  • licence: stop the 403/404 assignment-existence oracle (ae8a048)
  • licence: trim the Freigaben page for a receiving customer, gate row edits by scope (a561269)
  • licence: validate effective bounds and pull all assignment guards into the writer (b182e03)
  • licence: withhold per-version download and size figures from a receiving customer (e044d76)
  • licence: withhold the source reference from a receiving customer (bc430dc)

0.11.0 (2026-09-11)

Features

  • portal: organization-wide setup tab with org-scoped tokens (feabd4b)
  • registry: mount the read-only org-level endpoint prefix (79bb006)
  • registry: org-level access checks and the org-wide package union (fc2383f)
  • registry: organization-wide setup snippets (7599db0)
  • registry: serve composer metadata and dists organization-wide (6a48c83)
  • registry: serve npm packuments and tarballs organization-wide (d8c5411)
  • registry: serve the pypi simple index organization-wide (5b2e4e0)

Bug Fixes

  • admin: close the scope oracle in UpdateUpstreamRequest and remove dead helper (f71abea)
  • admin: finish the scope sweep on domains, upstreams and tokens (e80497a)
  • admin: make registry, mirror-source and git-credential guards respect the active scope (d10a62d)
  • admin: make webhooks, recipients, user/robot lists and the portal link honour org scope (4258838)
  • portal: give the Einrichtung tab a revoke control for org-wide tokens (33b8c81)
  • registry: apply own-beats-shared ordering to the org package pool (600f26f)
  • registry: drop unenforced version-constraint filter, gate /o/ by registry type (3d94b7b)
  • registry: exclude proxy-download routes from the /o/ org mount (5d4acc2)
  • registry: give each /o/ route its own name, close the write-route fail-open gap (31a5835)
  • registry: per-registry docker host in the org snippet set, single-source the /o/ path (89ebb8a)
  • registry: use Sie-form in the org write-refusal message (bc095c9)

0.10.0 (2026-09-09)

Features

  • admin: warn when a registry's organization has no customer portal (34a8227)
  • api-docs: add German summaries and groups for the API browser (dc43fc9)
  • mirror: continuous mirror sync — job, scheduler and publish exclusion (a105b06)
  • mirror: create and maintain mirror packages from the admin (6ed22a0)
  • mirror: import composer packages from a mirror source, dists included (4a405a6)
  • mirror: import npm packages from a mirror source, integrity-checked (a6d5dd7)
  • mirror: import python distributions via the PEP 691 simple API (7b9b53d)
  • mirror: let an operator retarget a mirror package's source (01fb3fa)
  • mirror: manage org-level mirror sources in the admin (dd5f8c8)
  • mirror: schema for org-level mirror sources and the mirror source mode (ee14445)
  • oci: a keep_untagged rule — untagged images survive N days by rule (1e09fa0)
  • oci: add the Docker registry's interface (setup, empty state, tags) (2fda534)
  • oci: add the retention policy schema and the columns the sweeper reads (6b1504b)
  • oci: address a registry by path namespace on the instance host (5895a43)
  • oci: administer retention policies, with an editor, dry run and guarded apply (f8d6d56)
  • oci: evaluate retention rules with OR, and a shield that vetoes rather than selects (194188a)
  • oci: exercise docker push/pull against a real docker client in E2E (b48ed75)
  • oci: honour keep_untagged windows in the sweep, as timestamps (bbd234e)
  • oci: let an operator opt into push-time repository creation (6c293b7)
  • oci: let an owning org admin assign retention and write inline rules (4c48452)
  • oci: live retention preview in the policy form and inline editor (1998f3d)
  • oci: mark push-created repositories so the sweeper can reclaim the empty ones (cd4e0bf)
  • oci: resolve and apply retention policies, with an audit trail (5880506)
  • oci: resolve retention through four tiers, inline rules first (4aeb20a)
  • oci: schema for inline retention rules, global policies and shared git credentials (3af64dc)
  • oci: share git credentials across organizations, checked at sync time (a35c605)
  • oci: show and assign a repository's retention policy on the package page (6dd0d13)
  • oci: sweep unreachable storage, expired uploads and empty push-created repositories (b36e272)
  • oci: the storage sweeper view (0e37f00)
  • portal: offer setup for every type a registry may serve (33e89b1)
  • portal: show a repository's retention policy and the next run's removals (12aefd6)
  • portal: show how to connect before the package list (13aa57d)
  • registry: accept oci blob uploads, chunked and monolithic (5e6dbfa)
  • registry: add docker as a fourth package type (3b7d6db)
  • registry: add OCI manifests and tags (0dcb80e)
  • registry: add the oci blob, manifest, tag and upload tables (7911e96)
  • registry: open the /v2/ endpoint with a basic-auth challenge (f67b75b)
  • registry: serve oci blob bytes on GET, local stream and s3 redirect (81b474e)
  • sidebar: nest E-Mail and Storage under System as a submenu (b5f4c25)

Bug Fixes

  • admin: measure Docker repository size from referenced blobs, not manifest documents (fc2a53c)
  • admin: stop hardcoding composer/npm/python lists across the package admin UI (23759d5)
  • api-docs: render fully German operation descriptions (acc535b)
  • correct stale docblocks, a migration placeholder and a test/name mismatch (1f65e8e)
  • e2e: give the worker a real healthcheck instead of disabling it (0c24b99)
  • e2e: make clean-store pulls independent of the daemon's image store (9b5a733)
  • http: stop exempting the bare /v2 from the post-size guard (4ae0ace)
  • i18n: render every relative timestamp in German (aaaf454)
  • mirror: close the final-review gaps in the mirror-packages feature (c08e605)
  • mirror: make import() iterate the same parsed entries the probe reports (5d75d08)
  • mirror: never splice UpstreamException's English text into a German sync_error (0377326)
  • mirror: refuse a MirrorSource type change while packages use it (31edd0c)
  • mirror: stage npm tarballs behind integrity verification, not just shasum (6437e3f)
  • mirror: sweep orphaned .part/.integrity-check staging on import (9de52cb)
  • mirror: use replaceHeaders() so PythonMirrorImport's Accept truly overrides (6e97e04)
  • oci: 403 on a non-global policy pick, and reset inline rules after clear (7125e96)
  • oci: bound the manifest request body at 4 MiB (ab8c660)
  • oci: challenge anonymous version pings on the path host (146fecd)
  • oci: close the version check's public-domain credential gap and pin path mode (71c7314)
  • oci: confine a corrupt inline rule set to its own package (e67766f)
  • oci: constrain the upload-id route and allow anonymous public version checks (0f6d56d)
  • oci: correct php.ini and Caddyfile body-size limits to close the anonymous DoS (80e96d7)
  • oci: drop the dead chunked-body matcher, bound it with memory_limit instead (438c336)
  • oci: exempt the OCI protocol from Laravel's own post-size guard (bb727fa)
  • oci: gate the blob read on what the caller may do, not on a flag (3607607)
  • oci: keep inline-rule input on screen when the server refuses it (5964c88)
  • oci: make push-time repository creation survive a real first push (d4c7c54)
  • oci: make the blob-gate rationale true and the leak assertion non-vacuous (b97b375)
  • oci: memoize platform lookup per manifest and cover it with tests (9132b7d)
  • oci: name the repository in tags/list the way the caller addressed it (e3de344)
  • oci: never delete a tag re-pushed between retention's evaluation and its delete (2b970af)
  • oci: one usable-in-scope query for git credentials, not three (8a31869)
  • oci: record when a tag was last pushed, distinct from when it was re-pointed (58ce254)
  • oci: refuse a repository name the packages table cannot store (0c5f97f)
  • oci: reset loading when the retention preview is cancelled mid-flight (2cf2e61)
  • oci: scope the blob push shortcut to the package's own organization (de25618)
  • oci: scope the request-body limit to Caddy, not global php.ini (0bab8ab)
  • oci: scope writes and shared-repository blob reads to their real tenant boundary (7a18d2d)
  • oci: stop the request-body caps from breaking bodyless POSTs and app uploads (d198236)
  • oci: throttle the inline retention preview, and cover its 409 (f22d085)
  • oci: usableByAny([]) matches nothing, not every global credential (0e4a7f2)
  • portal: attribute the entry band's copy to the organization (a87659a)
  • portal: build every install command from the registry that serves it (57a846a)
  • portal: close the review findings on the one install-command source (462f900)
  • portal: order the pull command and the tag table by one clause (59c385c)
  • portal: tell the truth when an organization may serve nothing (1f63ec3)
  • registry: close blob-download review gaps: HEAD leak, late readStream, buffer flush (3d38032)
  • registry: include docker in the default global registry-type ceiling (fe838bc)
  • registry: make the part-ordering and mount-comparison tests able to fail (c098a93)
  • registry: stop quadratic I/O on chunked blob uploads and close review gaps (26daab7)
  • registry: validate manifest digest pushes and close review gaps (d11e8bb)
  • sidebar: keep a submenu's children reachable in the icon rail (35efd0b)

0.9.0 (2026-09-07)

Features

  • admin: assign a shared package to any registry, refusing name collisions (51a376c)
  • admin: choose who may share packages, and date a shared assignment (9e8d63b)
  • admin: let an authorized operator share a package (8cd7322)
  • admin: let an operator change a registry slug (e26c2c0)
  • admin: let an operator change an organization slug (c12e8ed)
  • admin: let only the owner's administrators assign or withdraw a shared package (0cc514f)
  • admin: name the portal address in the slug change confirmation (c5f2e06)
  • packages: add the shared flag and the setting that governs it (8cd64c0)
  • portal: address the portal by organization and let the operator switch it off (172713c)
  • portal: carry each registry own availability date on its entry (86dd26f)
  • portal: compose the customer package list from what the registries serve (3880fd5)
  • portal: give the registries area a way in (dd5fcdf)
  • portal: make the package list the customer landing page (85be34f)
  • portal: say whose portal an operator is looking at (b9b48fd)
  • portal: scope the registry pages to the addressed organization (e0c03ba)
  • registry: count an assigned shared package as hosted locally (376a35c)
  • registry: redirect pre-org-scoped registry urls to the canonical form (e64e294)
  • registry: resolve a shared package assigned to the registry (30035ac)
  • registry: scope the registry slug to its organization (5be25aa)

Bug Fixes

  • admin: ask the ownership question the resolver asks, over the name and not the row (e38d239)
  • admin: honour available_until in the shared-package guard, and fix its copy (09906f3)
  • admin: let a share be withdrawn immediately, and stop the note misattributing an outage (afdb3d7)
  • admin: name the one legacy address that survives an organization rename (e12ccf9)
  • admin: pin the pivot no-op the permitted re-submission rests on (9a2196a)
  • admin: show the /r/ path pattern, not bare slugs, in the org slug dialog (7e100df)
  • admin: sort and search the registry list on the column it actually shows (7f5eeeb)
  • admin: state the ownership rule existentially in the comments and the German too (2625859)
  • admin: state the shared-package rule over the resulting set, and close the mirror (a19ce6c)
  • admin: stop a partial organization update from disabling a customer portal (3e5037f)
  • admin: stop claiming the old /r/ addresses survive an organization rename (d22bd36)
  • admin: stop telling an operator to detach a name that detaching will not release (4746c8d)
  • api: mark a lapsed registry assignment instead of returning it unmarked (349e766)
  • docker: keep bin/ and phpunit.e2e.xml out of the production image (9571d22)
  • e2e: escape pip token safely, reject a second bad bin/e2e argument (2e1e617)
  • e2e: keep the composer install offline and assert the installed version (138096f)
  • e2e: make the composer install test distinguish a dist install from a git fallback (289b6d7)
  • e2e: raise the twine pin instead of freezing the fixture's setuptools (d756b14)
  • e2e: register the npm package the seeder never created (4899a61)
  • e2e: reuse the shared npm auth-key derivation and tighten the PyPI version check (f6e6f21)
  • e2e: route the missing-context guard through fail() in bin/e2e (fabf28c)
  • e2e: seed the python package and cover both publish-based rows (6f66594)
  • e2e: tighten the refusal assertion and centralize the npm auth key (340b1cc)
  • e2e: use the read token for the pip install test, not the leftover publish one (463e2c1)
  • i18n: unify German address form to formal Sie across user-facing text (703cb78)
  • packages: close a same-table slug race and correct guard docs (c7837d2)
  • packages: close the organization/registry slug claim race (521a2ff)
  • packages: compare python names PEP 503-normalised when refusing a shared collision (7691aa6)
  • packages: derive the repository-url scheme guard from config (52be28e)
  • packages: govern share-packages by operator-org maintainer, not admin (e1cbca8)
  • packages: re-seed the sync status on resync and say when polling gives up (1e069d8)
  • packages: reconcile the sync status instead of waiting for a broadcast (166ae97)
  • packages: require SlugClaimGuard::claimRegistrySlug's organizationId (07cc85d)
  • portal: ask the portal switch before the policy, so one surface has one answer (82c4f23)
  • portal: bind the registry pages to the address and to what the registry serves (df7f6fb)
  • portal: bind token revocation to the addressed organization (7b06717)
  • portal: correct the number and the claim in the portal package copy (430216a)
  • portal: drop the package pivot so a wrong date cannot be read off it (ad71dfa)
  • portal: gate the setup tab's publish offer and drop the last inline membership check (c1ebbd9)
  • portal: give an account with no home organization a page instead of a 500 (12aec2d)
  • portal: keep a registry hidden from the portal out of the package list (4f75c07)
  • portal: link a lapsed registry from the landing page too (2e587c0)
  • portal: mint tokens for the organization the portal addresses (cf0a95f)
  • portal: refuse a hidden registry in the controller, not only in the policy (bae7eb7)
  • portal: refuse a hidden registry when minting, in the controller not the policy (984ec35)
  • portal: require membership for the publish offer, not only administers() (88391df)
  • portal: say which registries the lapsed note is about (1a7ed69)
  • portal: scope the publish offer to the addressed organization (15f8f83)
  • portal: state the consequence for a package only some registries still serve (2a85a45)
  • portal: stop the portal reporting a lapsed assignment as live (342d920)
  • registry: answer HEAD on a legacy url like GET, not like a write (823202f)
  • registry: choose the resolvable package, not the first-sorted one (a1aa768)
  • registry: correct stale legacy-slug comments and test creation order (11ca326)
  • registry: freeze the pre-upgrade legacy address in groups.legacy_slug (879ef49)
  • registry: keep suppressing the fallthrough for a lapsed shared assignment (96b35de)
  • registry: keep the legacy redirect correct under a subdirectory deployment (d6fded6)
  • registry: refuse an ambiguous legacy slug and catch pip's per-project url (2e2dd4f)
  • registry: seek the registry by organization, and keep the slug namespaces apart (6066e53)
  • seeder: make the E2E composer package actually git-sourced (d3ded89)
  • seeder: refuse every environment but local/testing, and prove the guard fully (de02248)
  • setup: keep the wizard from deriving an organization slug a registry already holds (b80ae4a)
  • tests: close three review minors on the PHPStan/Pest-plugin work (5e42bfe)
  • tests: resolve genuine PHPStan level 6 findings under tests/ (1225632)
  • ui: address the reader as "Sie" on the portal's token surfaces (bf1c9ee)
  • ui: make the success toast dismissable and self-dismissing (4053d9e)
  • ui: stop linking a package the operator is not allowed to open (6e1a057)

Performance Improvements

  • admin: skip the organization list for a caller who administers every one (15df89e)

0.8.0 (2026-09-02)

Features

  • admin: own a created package where its registries are owned (da329f4)
  • packages: give a package an owning organization (7213730)
  • packages: scope the package name to its organization (f6ddc25)
  • registry: resolve a package within the addressed organization (aebffb7)
  • registry: scope the dependency-confusion guard to the organization (a56b2da)

Bug Fixes

  • admin: refuse deleting an organization that still owns packages (2191334)
  • api: refuse deleting an organization that still owns packages (17da89d)
  • migrations: report the org-less registry before the ownerless package (8205adc)
  • policies: stop GroupPolicy::view from crashing on a null organization_id (6ec70c5)
  • registry: keep the organization null-guard truthful in RegistryAccessService (b8e9053)
  • registry: refuse cross-organization package assignments at migration time (5ed6f4f)
  • registry: scope the registry access service to the addressed organization (db677fc)
  • tests: pair factory packages with their registry's organization (35a1965)

0.7.3 (2026-09-02)

Bug Fixes

  • admin: send a submitted create form somewhere that shows the result (c5a7047)
  • probe: authenticate the manifest read and stop hiding when it fails (e779888)

0.7.2 (2026-09-02)

Bug Fixes

  • admin: allow toggling trusts_email_claim on existing OIDC providers (a6d5e03)
  • admin: keep upstream credentials out of the session and say so in the form (522941a)
  • admin: redact upstream mirror credentials from the console (d850492)
  • admin: surface the real reason a package probe failed (5cc230f)
  • auth: gate OIDC email-claim auto-linking behind per-provider trust (11e99dd)
  • logging: rotate by default, keep the suite out of the dev log, cap Docker logs (94d8634)

0.7.1 (2026-08-27)

Features

  • admin: resync a package from its detail page (84624cf)
  • vcs: self-heal a foreign-owned git mirror by displacing it instead of failing forever (4dfda2a)

Bug Fixes

  • 0.7.1: address whole-branch review findings across resync, mirrors, and host trust (483c3d4)
  • http: let the health endpoint answer under any host (59a9bf0)
  • vcs: abort a contended mirror sync instead of racing it, and stop shaving the lock TTL (711489b)
  • vcs: close round-six's two Important findings and three cheap Minors (a5a6fa1)
  • vcs: pin mirror check to its path and never delete on uncertainty (e847067)
  • vcs: re-clone an unusable mirror and name a foreign owner (0f0d49c)
  • vcs: size the mirror lock timings against the work they guard (8fc8b69)
  • vcs: split the mirror lock budget by caller and close the kill paths (bd73166)

0.7.0 (2026-08-20)

Features

  • activity: add a detail dialog showing changed fields and the raw payload (665f375)
  • activity: add a JSON viewer that renders values as escaped text (c37f120)
  • activity: add a validated page size and a newest/oldest direction toggle (e1347ac)
  • activity: group log entries by day as tested logic (40f27eb)
  • activity: replace the activity list with a timeline grouped by day (bdbae7c)
  • admin: choose a notification cadence per organization (7a72038)
  • admin: let an operator retire a package from its detail page (c748e6c)
  • admin: manage notification recipients and their subscriptions (244a407)
  • admin: move both webhook creation forms onto their own pages (abfa77d)
  • admin: move the provider, token and package forms onto their own pages (34bc5c5)
  • admin: move the user create and edit forms onto their own pages (c2fb3ee)
  • admin: move upstream and git-credential forms onto their own pages (35fa3cd)
  • api: expose and set package abandonment over the v1 API (4b06e59)
  • auth: implement MustVerifyEmail so the verification gate actually gates (4c69eb0)
  • composer: mark abandoned packages in the metadata document (24b50a0)
  • docs: let an operator decline the third-party API browser (d3614ec)
  • listings: add a sortable, filterable DataTable and use it for users (9c8ded5)
  • listings: sort and filter credentials, robots, tokens and upstreams (53d7b49)
  • listings: sort and filter domains, organizations, groups and providers (e8ef126)
  • listings: sort and filter webhooks, the portal registry and token settings (1fbba72)
  • listings: sort packages and activity server-side behind a column whitelist (03e1a6c)
  • notifications: add recipients, recorded events and a per-organization cadence (3b41d53)
  • notifications: add the event taxonomy and the digest folding rule (a059fcc)
  • notifications: record sync and webhook failures for the digest (18d3748)
  • notifications: send a folded failure digest per recipient (9cb42a3)
  • npm: deprecate every version of an abandoned package (b3a55fc)
  • packages: add a column for the rendered project readme (1162696)
  • packages: add the value object that words an abandonment (b6429df)
  • packages: convert existing npm git-mirror packages to publish (6f0ca7b)
  • packages: make the enum decide which source modes a type may use (c32a4e9)
  • packages: order package versions semantically for both detail pages (62b71b2)
  • packages: reject the git-mirror mode for npm on both create paths (e951562)
  • packages: store an abandonment with its replacement and reason (8ab60c7)
  • pypi: publish a PEP 792 project status for abandoned packages (c8bdeda)
  • pypi: serve the Simple API at version 1.1 (1c0490c)
  • setup: scope the npm snippet and show both registry addresses (527c2e1)
  • sidebar: keep nav sections collapsed unless they hold the current page (7eb93d9)
  • sync: store the project readme without ever failing a sync over it (93e6dda)
  • types: enforce Ziggy route names and params at compile time (92ab2d2)
  • ui: offer only the source modes a package type actually allows (1b9e678)
  • ui: replace boolean checkboxes with the Switch component (6c2f896)
  • ui: replace the collapsing version list with a version selector (7cdea9a)
  • ui: show the project readme on both package detail pages (4331e3c)
  • vcs: locate a project readme in the bare mirror (112b416)
  • vcs: render a repository readme to sanitized html (d4bb958)
  • webhooks: announce a delivery failure once, after the last attempt (ba0d555)

Bug Fixes

  • 2fa: gate two-factor enrollment behind password confirmation (5db67a5)
  • admin: bind the package group checkboxes to the checked event, not modelValue (7cdccfd)
  • admin: give the repository probe a budget, a record and one non-distinguishing error (d0e7076)
  • admin: keep three query-string ids away from the Postgres uuid comparison (d03b9b0)
  • admin: pass the user form via provide/inject instead of a prop (bc90a99)
  • api-keys: bound a successor key by the key that minted it (f56096f)
  • api: clamp per_page on the five /api/v1 collections at both ends (d8c6236)
  • api: close the orphan-claim hole the web half already closed (dddc4f8)
  • api: end the self-renewing chain a never-expiring API key could mint (a4aa8da)
  • api: replace the wildcard CORS default with the instance's own origin (f732189)
  • api: stop a leaked super-admin key from moving an account's reset channel (02245c3)
  • auth,admin: restore the password label's for and the header breadcrumbs (ffcd9ea)
  • auth: add an account-scoped counter to the login throttle (65be613)
  • auth: bound account-targeted password guessing without a lockout button (a0f1af7)
  • auth: derive the login timing dummy from the active hasher (206a04e)
  • auth: evict other sessions on password change and reset (55e8eb1)
  • auth: give the password-confirmation account bucket the power to refuse (795e26f)
  • auth: give the reset-completion endpoint its own throttle bucket (54b0720)
  • auth: make one email address mean one account, whatever its case (1c8a936)
  • auth: make the login delay pool pace guesses instead of switching off (866b635)
  • auth: make the password-confirmation gate satisfiable without a password (1be1209)
  • auth: meter every password comparison, not just the confirm screen (bd07cb4)
  • auth: narrow the password-confirmation window from three hours to fifteen minutes (a46063a)
  • auth: rate limit POST /register (9f63a23)
  • auth: rate limit the password-reset endpoints (1a9c5c3)
  • auth: stop reset-password from confirming whether an address exists (d7ddf78)
  • auth: stop the account login counter from refusing a correct password (bebca80)
  • auth: throttle, log and correctly scope the password-confirmation gate (95f7b53)
  • auth: write a record for failed and throttled authentication (77532ea)
  • broadcast: compare UUID keys as strings on the private user channel (df69480)
  • broadcast: do not subscribe to the operator channel without the right to (bb88eca)
  • broadcasting: stop the reverb guard from crash-looping the shipped compose (e834c65)
  • broadcast: refuse a websocket server running on the published app secret (e20cfdd)
  • broadcast: restrict the operator channel to super-admins (8cd4191)
  • ci: widen the runtime-props gate to every component, not just ui/ (2514b78)
  • composer: strip an abandoned key the tag manifest tried to plant (b30eede)
  • config: stop a scheme-less APP_URL from switching off every host control at once (fd36eb3)
  • credentials: gate every credential-minting route, not just settings (161627b)
  • credentials: gate registry tokens and API keys behind password confirmation (d55b18f)
  • deps: declare the php floor the lockfile actually requires (fb14a48)
  • docker: give the scheduler the artifacts volume it prunes (45bfa0c)
  • docker: ignore the Vitest config and its test files (a51e8e2)
  • docker: make the build context an explicit decision instead of a stale list (a70de56)
  • docker: run the container as www-data instead of root (49278a9)
  • docker: stop publishing the app and reverb ports and document the hardening env (42d7483)
  • docs: keep the api-browser switch from leaking out of its own test (b0e0cf0)
  • domains: reserve registry hostname attachment for the instance operator (c90fa97)
  • forms: correct v-model target types across admin forms (c0b0e99)
  • frontend: drop stale tailwind.config.js references (ed4447e)
  • frontend: keep tailwind-merge in dependencies, where cn() needs it (9c3c642)
  • frontend: use Tailwind 4 syntax for custom properties in arbitrary values (000c334)
  • groups: match the Kunde/Org filter on organization_id, not name (463a95d)
  • groups: reject cross-tenant package ids on every attach path (5e729cd)
  • headers: apply security headers to the stateless routes and add an enforcing CSP (cbecef6)
  • headers: keep the documented enforcing CSP from blanking two operator pages (747d9cb)
  • headers: name the websocket origin in the CSP instead of allowing every host (cd5dea1)
  • health: serve /up ourselves instead of Laravel's CDN-loading health page (774df3a)
  • http: decide the generated-URL root per request instead of pinning it at boot (e7bb1e2)
  • http: stop the Host header from choosing where a reset link points (ab88a70)
  • inertia: redact this application's own secrets from devtools recordings (d1949ba)
  • kontorfix: align GroupSheet's local Pkg type with PackagePicker's (3a550a0)
  • listings: fix DataTable's prop mutation and loosen the row-type constraint (49d470d)
  • listings: restore empty-state markup and honour sortAs: number (2f99488)
  • mail: keep the configured default when a setting has no mailer (2984458)
  • notifications: close the whole-branch review findings on the failure digest (db503f5)
  • notifications: deliver failure digests per recipient, not per event (996cb8e)
  • notifications: isolate the delivery insert and close review minors (474014b)
  • oidc: block auto-link for accounts privileged from any source (bc43aa8)
  • oidc: match an asserted address case-insensitively (ac704c7)
  • packages: answer a disallowed source mode in German (5ac9761)
  • packages: authorize git_credential_id on every create path (a2c7d92)
  • packages: bind the inline repository token to a port, not just to a hostname (ff2daad)
  • packages: cover portal version ordering and correct a comment (b9bec48)
  • packages: create a quick-added package into its registry, not into limbo (eca8723)
  • packages: fix sync error messages and gate resync dispatch by source (f05a99a)
  • packages: keep a git-sourced package's repository url required on update (f2ec731)
  • packages: make the remove-the-repository-url remedy possible (c6cefb4)
  • packages: refuse creating a package into no registry at all (05043f2)
  • packages: state npm publish-only as a decision, not a universal fact (269cc41)
  • packages: stop a registry-less package being claimable by any tenant (da0adba)
  • packages: stop recommending an impossible remedy and stop reporting a declined resync as success (83b6eaf)
  • packages: stop repository_url reaching the operator tier and the audit log unredacted (3000326)
  • packages: stop the package detail page listing foreign registries (2532da4)
  • packages: unbreak composer creation and apply source_mode on the api path (c138a37)
  • packages: withhold a git PAT in repository_url from member tier (2d8d95a)
  • portal: stop pre-filtering the registry package list server-side (509e5c7)
  • profile: never clear the email verification without delivering a challenge (9543e46)
  • registry: apply the artifact size cap to the bytes as they arrive (238a829)
  • registry: close the malformed-id 500 that the UUID pin left open (23d2a24)
  • registry: invalidate personal tokens on deprovisioning and allow an expiry (8a79a30)
  • registry: keep a proxy artifact key inside the upstream it belongs to (4c4f736)
  • registry: refuse a relative path component in a proxied package name (90a485f)
  • registry: refuse a relative path component in a pypi project name too (8683e87)
  • registry: revoke instead of delete, and only on real deprovisioning (d51bd60)
  • registry: stop the pypi fallthrough disclosing the mirror credential (eebb242)
  • settings: give passwordless accounts a way to disable 2FA and delete themselves (45451b9)
  • settings: re-prove the password before moving the account's recovery address (a07a914)
  • setup: fail closed when the first-run token is missing or unreadable (be62f1b)
  • setup: read the first-run token from the body, not from the query bag (6c6028a)
  • setup: take the first-run token out of the URL and into a POST body (b70d8b9)
  • ssrf: close the four IPv4 ranges filter_var leaves open (14edfed)
  • ssrf: fail closed when the outbound address policy cannot resolve a host (a87e960)
  • support: split DigestLine into its own PSR-4-mapped file (676e52c)
  • sync: clear readme_html when the repository no longer has a readme (8d76752)
  • sync: refuse a package the job should never git-sync (c9118f9)
  • tests: give each checkout its own database and temp directory (27da83c)
  • tests: match ** at any depth in the .dockerignore matcher (ff9d8bf)
  • tests: pin the activity whitelist test to sort key and row order, not echoed params (dc4e06c)
  • tokens: restrict publish registry tokens to org admins/maintainers (0b2fb4d)
  • tokens: scope shared-token revocation to the owning organization (6a050bc)
  • ui: render the intended element instead of falling back to a div (47f2047)
  • ui: restore the runtime props that a named props interface silently dropped (b953585)
  • ui: stop naming a nonexistent tab and deduplicate readme rendering (0d41345)
  • upstream: bound the proxied artifact cache with a budget and a prune (de22c71)
  • upstream: bound the work an uncacheable proxy artifact costs, not just the disk (a8aedbc)
  • upstream: never commit a truncated transfer to the artifact cache (b7e58b4)
  • upstream: never send the mirror bearer token over cleartext http (a18e7a5)
  • upstreams: authorize the retarget guard before it reads the stored token (9f48c8f)
  • upstreams: refuse to retarget an upstream that keeps its mirror token (955925d)
  • upstreams: withhold a mirror credential in upstreams.url from member tier (90f66ee)
  • vcs: apply a transport and address policy to every outbound git call (5f8ffb5)
  • vcs: bind a git credential to the whole authority, port included (33cb0c1)
  • vcs: bind stored git tokens to the host they were issued for (9cd53d7)
  • vcs: distinguish readme parse failures and harden stored links (2ce31b5)
  • vcs: enforce the readme size cap before the blob is read (9dc5c44)
  • vcs: filter tree entries by type and respect fence length in readme locator (8d29b96)
  • vcs: make the backfill's refusal to bind a git credential mean refusal (cc95cad)
  • vcs: refuse git redirects on the tokenless path as well (4729502)
  • vcs: skip symlinked readmes instead of showing their target path (940e697)
  • vcs: stop the capped-read abort signal escaping into unrelated code (33783c0)
  • vcs: stop the host backfill from blessing an operator-chosen host (bd56b53)
  • vcs: strip images from rendered readmes and unwrap dead links (f01fbfd)
  • vcs: write the truncation notice in the syntax that will render it (95ee4af)
  • webhooks: 404 a malformed incoming-webhook id instead of raising a 500 (3b81b54)
  • webhooks: partition the incoming-webhook audit ring per hook (e611848)
  • webhooks: prune the incoming audit as two rings so a flood cannot erase it (956d7b6)
  • webhooks: verify bitbucket by body signature instead of a URL bearer (7973ebc)

0.6.0 (2026-08-07)

Features

  • models: mark encrypted/hashed secret columns as (0958a2b)

Bug Fixes

  • probe: discover the package name from pyproject.toml (c51014b)
  • probe: stop the ls-remote HEAD filter from hiding (27a90fa)

0.5.0 (2026-08-07)

Features

  • packages,upstreams: editable git source on packages + (48acde5)
  • registry: git-mirror source mode for npm & Python + (4964692)
  • vcs: managed git credentials (multi-provider) + (e69cf99)
  • vcs: private git repo sync via access token + (79db0f9)

Bug Fixes

  • ui: clearer create-dialog hints for publish-based vs (ec2d9b4)
  • ui: enforce probe-first on submit, not just the (22ded02)

0.4.0 (2026-08-06)

Features

  • api: per-rights scoping for the whole v1 API + status (c8b884b)
  • dashboard: failed-packages widget + coverage lift (6c1f047)
  • pypi: pip/twine setup instructions in portal, package (5022de1)
  • registry: add pypi-registry (07dd382)
  • registry: enable/disable registry types (global ceiling (145351f)
  • sidebar: collapsible navigation sections (2f5ebc0)

Bug Fixes

  • api: restrict the v1 management API to super-admins (64942e3)
  • ui: keep tall dialogs inside the viewport with an (c3f2ba5)

0.3.0 (2026-08-05)

Features

  • admin: multi-org users, user edit, registry UX, robots (c37f86e)
  • admin: system settings hub, toggleable registration, token-gated setup (5c634f1)
  • audit,docs: activity log across the app + REST API (281a4c2)
  • packages: preview a repository before creating a (512f7cd)
  • roles: org-detail membership roles + global/org-scoped (eff9210)
  • roles: per-organization roles + global super-admin + (05e9ab8)
  • stats: per-package & per-registry download/storage (d85c984)
  • ui: search trigger, activity tabs, API browser (3f417a5)
  • ui: searchable, keyboard-navigable select replacing (2a5fefd)
  • webhooks: manageable incoming endpoints with (b8b18f5)

0.2.0 (2026-08-05)

Features

  • setup-wizard + mail + postal (d1891bb)

0.1.1 (2026-08-05)

Features

0.1.0 (2026-07-28)

Features

  • accept bearer tokens for npm clients in registry auth (d9fa682)
  • account settings page for personal access tokens (4dfa473)
  • add api key model with hashed issuance (533f72b)
  • add domain model factory (7cd3b29)
  • add optional owner (user_id) to registry tokens (640bbc2)
  • add robot account type to users (7bc8831)
  • add shadcn-vue tabs component (4543c8c)
  • admin gui for oidc providers with discovery (5444fad)
  • admin gui for storage backend with connection test (6147ad3)
  • admin package detail page with versions, dependencies and groups (438fd4a)
  • admin package management with inline group assignment (fe3493b)
  • admin registry detail page (packages, domains, upstreams, tokens, setup) (02035ae)
  • admin robot account management (f919454)
  • admin status page with operational health checks (a71f15b)
  • assign a registry to a customer organization on creation (b5bdd13)
  • auto-generated openapi docs at /docs/api behind operator gate (28ed620)
  • bearer api key auth, versioned api routing and me endpoint (ce8bf5a)
  • block robot accounts from interactive login (59d677d)
  • brand the invitation email with the kontorfix palette (0b27c61)
  • broadcast package sync events on a private operator channel (4c5787e)
  • browser webauthn ceremony helpers (81feae1)
  • central registry access service with acl matrix tests (f83924e), closes #28 #84
  • composer packages.json and p2 metadata endpoints with acl (d1abb9d)
  • composer upstream proxy with dist-url rewriting and strict mode (139a2f7)
  • composer v2 metadata builder with minified output (c2b7118)
  • core schema for packages, versions, groups, domains and registry tokens (bf98767)
  • customer organization management and vendor detail page (974fbaf)
  • customer portal registry overview and detail with setup snippets (4a1e472)
  • customer self-service token management scoped to own org (fc315f0)
  • db-backed configurable artifacts storage (local/s3) (385d225)
  • derive npm tarball name server-side; e2e flow + real publish/install smoke test (2899d28)
  • domain management gui per group (da4fa44)
  • edit registry name and visibility (slug stays immutable) (3c3009d)
  • git repository service for mirror, tags, file-at-ref and zip archive (d375290)
  • global command palette (cmd+k) package search (532132f)
  • global search across packages, registries and customers (be0d24a)
  • group and token policies enforcing org boundary (f122f79)
  • group management with fluid package assignment sheet (9c1f464)
  • group the sidebar navigation into labeled sections (adb9cef)
  • health service for status page (db, cache, queue, storage, upstreams) (e6b1574)
  • hourly re-sync of vcs packages via the scheduler (86c6089)
  • incoming webhooks trigger package resync on push (8b9bcb3)
  • inline package creation in PackagePicker (684e7ab)
  • invite users by email with a set-password link (b9b1676)
  • kontorfix landing page and brand logo, drop starter-kit welcome (dbd39f4)
  • lazy dist build and authenticated zip streaming (7318399)
  • live sync-status updates via laravel echo (b39ac3b)
  • manage domains and upstreams inline on the registry detail page (f457f7f)
  • npm packument and tarball endpoints with shared acl (40521ed)
  • npm packument builder with dist-tags and tarball urls (a98a499)
  • npm publish with tarball storage, integrity and version-conflict handling (b2acb2f)
  • npm schema — dist-tags, nullable source ref, tarball dist fields (7a112db)
  • npm upstream proxy with tarball-url rewriting and strict mode (3bb762e)
  • oidc authorization url builder with pkce (7ac8437)
  • oidc code exchange and id_token jwks verification (67c0449)
  • oidc discovery with ssrf-guarded endpoint resolution (ff3b5a9)
  • oidc login flow with identity linking and safe provisioning (b3a8819)
  • oidc provider and identity schema and models (6f7bd84)
  • operational dashboard with real stats, surface oidc/storage/status in nav (8c7ce5e)
  • organizations rest api (3cde2ae)
  • outgoing webhooks with hmac signing, retry and delivery log (216b61c)
  • package dependency extraction from version metadata (a4412a9)
  • packages rest api (e7ef559)
  • passkey login is full strong auth, may replace the totp step (c91ea94)
  • passkey management settings page with owner-scoped deletion (10d1b26)
  • passkey settings ui and passwordless login button (4902ba2)
  • personal access token management in account settings (f18196c)
  • personal api keys settings page (9bd96a6)
  • proxy artifact download with cache-on-first-hit (6a864eb)
  • read-only package detail in the customer portal (9665032)
  • registries rest api (c78f2d4)
  • registry sub-resource rest api (domains, upstreams, package assignment) (04da9ca)
  • registry token management with one-time plaintext display (8b6e21d)
  • registry tokens rest api (5c8815b)
  • registry tokens with hashed storage and basic-auth middleware (3832375)
  • registry url resolver for portal (domain or slug path) (4e864b6)
  • reject robot web sessions defense-in-depth (covers passkey login) (3e7dcfd)
  • resolve registry groups by custom domain and serve at the domain root (87c7cdd)
  • restrict horizon dashboard to operator admins (15f6f7d)
  • reusable registry setup widget with create-and-insert token (b2a60d7)
  • revalidated redirect following for proxy artifacts + e2e proxy flow tests (a2e0c48)
  • reverb container and operations docs (f6e9f0c)
  • role-based navigation, redirect members to portal (8d8d4b4)
  • run horizon in the worker container and link the dashboard (cedcdd0)
  • scaffold laravel vue starter kit with ddev, pint, larastan, pest (322ff8b)
  • schedule cleanup of failed jobs, delivery logs and horizon snapshots (7c80025)
  • search and filter the customer portal package list (d01f073)
  • security headers middleware and configurable trusted proxies (812448c)
  • self-service api key management endpoints (4c01f66)
  • server-side filters for the package list (7178ea4)
  • setup snippet builder for composer/npm client config (d7b1ee0)
  • sso login buttons and oidc operator documentation (c6a7644)
  • sync job importing tagged versions from vcs (8b7f64b)
  • tabs and create-and-insert setup in the customer portal registry (04d9d55)
  • tabs and inline token management on the registry detail page (d29389f)
  • tabs on the package detail page (5206dd3)
  • two-factor authenticator service (totp verify, qr, recovery codes) (1cece3c)
  • two-factor columns and helpers on user model (11d03d4)
  • two-factor enrollment, confirmation and disable in settings (1bb08b6)
  • two-factor settings and login challenge ui (952b5c0)
  • two-step login with totp challenge and recovery codes (ff6d267)
  • type-aware package name validation (npm scoped/bare, composer vendor/name) (2b3d72b)
  • upstream http client and metadata/artifact cache (b94bbec)
  • upstream management gui per group (2de5fd1)
  • upstream, allowlist and metadata-cache schema (fc30be9)
  • user invite/set-password toggle and resend action in the gui (7d3d780)
  • user management with org and role assignment (be70fb0)
  • users and robot accounts rest api (681aff1)
  • uuid v7 keys, organizations and user roles (bf0ca38)
  • webhook and delivery-log schema (5f0c675)
  • webhook management gui with delivery log and incoming setup (70975ee)
  • webhooks and status rest api (11a405b)
  • wire user model to passkey authentication (cb7f041)

Bug Fixes

  • 502 for upstream errors on custom domains + shadowing/acl-parity tests (8a0ea08)
  • bind admin routes to the operator org, protect operator-admin invariant (540912d)
  • block webhook delivery to internal targets (ssrf) (c651cca)
  • dashboard test uses non-member role after portal redirect (c06c904)
  • docker build — ignore platform reqs in vendor stage, add posix ext (c6eb5f0)
  • enforce org-scoped authorization on npm publish (critical) (449e04b)
  • enforce personal token ownership on revoke and portal listing (169b630)
  • fire sync.failed once on terminal failure, no redirects on webhook delivery (f429c28)
  • harden git wrapper against option injection, path traversal and temp leaks (2f39a7f)
  • ip throttle on api surface, robot-only api keys, robot passkey block (af0bf87)
  • only return customer search results to admins (243da1b)
  • order api.auth before throttle so rate limiting is per key (6032127)
  • per-key api rate limiting and guard api user deletion (6d8e75f)
  • pivot datetime cast, reverse-lookup indexes and null-on-delete group ownership (be9707a)
  • prevent private-name leak to upstream, 502 on upstream error, no fake dist (4ec82ce)
  • property annotations for registry token timestamps (98e7577)
  • reject bracketed ipv6 literals in ssrf guard (critical) (ed4479a)
  • reject nat64 and ipv4-compatible ipv6 embeddings in ssrf guard (245d537)
  • remove dead-end create button, add fetch error handling and org-scoping todos (68b384f)
  • sha-keyed dist cache, atomic writes and temp cleanup on dist download (35fcc13)
  • sidebar nav items use href instead of undefined url (39dea26)
  • ssrf-safe metadata fetch and drop upstream auth on cross-host redirect (404e044)
  • stable release dates, semver-based latest, retries and per-tag resilience in sync (19429cc)
  • strict-mode + ssrf hardening on proxy artifact download (4c05a1d)

Performance Improvements

  • index-backed exists check for package access instead of pool hydration (fc9a80c)
  • throttle last_used_at writes and pin token expiry boundaries (9b2653f)