Skip to content

feat: admin-provisioned OCI registries via config.yaml - #477

Open
tylerpotts wants to merge 21 commits into
mainfrom
feat/config-managed-registries
Open

feat: admin-provisioned OCI registries via config.yaml#477
tylerpotts wants to merge 21 commits into
mainfrom
feat/config-managed-registries

Conversation

@tylerpotts

@tylerpotts tylerpotts commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Closes #475

Summary

Admins can now provision OCI registries for all users declaratively, and remove the built-in default registry.

Note (2026-08-07): requirements changed to support public OCI registries only. Credential fields (username/password/api_token), ${ENV_VAR} expansion, and credential encryption were removed from this PR; authenticated registries can still be added per-instance through the admin UI/API/CLI as before.

  • New optional registries: section in config.yaml: a seed_default flag plus a list of entries (name, url, namespace, default). Entries are public registries and carry no credentials.
  • At boot (both team and local mode), entries are reconciled into the oci_registries table in one transaction, keyed by the unique name: created/updated, marked config_managed, and removed when dropped from config. Name collisions with user-created registries are taken over by config with a logged warning (any credentials the user-created row had are cleared). The upsert is concurrent-boot safe (savepoint + duplicate-key fallback) for shared-Postgres deployments.
  • Config-managed registries are locked: update/delete via API/UI/CLI returns 409, and the default flag cannot be stolen from a config-managed default by creating/updating another registry. The admin UI shows a "Managed" badge and disables edit/delete.
  • registries.seed_default: false disables seeding of the built-in quay.io/nebari_environments registry. Independently, the seed is now one-time (tracked by a marker in a new system_settings table), so deleting the default registry via the admin UI finally sticks across restarts. Existing databases get the marker backfilled without being touched.

Companion chart PR for the data-science-pack (mounts this config into JupyterHub user pods): nebari-dev/data-science-pack#202

Test plan

  • Config parsing/validation unit tests
  • Reconciler behavior tests: create, update, takeover (including credential clearing), stale removal, remove-then-re-add, default switching (9 cases)
  • Seed flag + one-time marker tests, including backfill for pre-existing databases (4 cases)
  • Service-level and HTTP-level 409 locking tests, default-steal protection tests
  • Frontend component tests for the Managed badge and disabled actions
  • End-to-end smoke test: nebi serve in local mode with a config-defined registry serves it via /api/v1/registries with config_managed: true, default seed suppressed; default seed still works with no config
  • Full suites green: go test ./internal/..., frontend vitest (185 tests)

@netlify

netlify Bot commented Jul 30, 2026

Copy link
Copy Markdown

Deploy Preview for nebi-docs ready!

Name Link
🔨 Latest commit a511a19
🔍 Latest deploy log https://app.netlify.com/projects/nebi-docs/deploys/6a76303de8abd400084afcb9
😎 Deploy Preview https://deploy-preview-477--nebi-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@tylerpotts
tylerpotts marked this pull request as draft August 3, 2026 14:10
@tylerpotts

Copy link
Copy Markdown
Collaborator Author

Added a cherry-pick of #490 (netguard allowed-origins fix, issue #489) so the pr-477 image is testable behind jupyter-server-proxy. Will drop the commit in a rebase if #490 merges first.

Local mode rejects any request whose Origin header is not a loopback
origin. Behind a reverse proxy on a public hostname (JupyterHub's
jupyter-server-proxy in the data-science-pack), browsers send the proxy's
origin on CORS-mode subresource requests - Vite emits the SPA bundle as
<script type=module crossorigin> - so every JS/CSS asset request got a
403 and the UI rendered a blank page (#489).

Add server.allowed_origins (NEBI_SERVER_ALLOWED_ORIGINS), a comma-
separated allowlist honored by both netguard's request check and the
CORS response headers, which crossorigin fetches also require.
@tylerpotts
tylerpotts marked this pull request as ready for review August 5, 2026 14:00
…dential support

Requirements changed: admin-provisioned OCI registries support public
registries only. Remove username/password/api_token from the config
schema, the ${VAR} env expansion (which existed only for credentials),
and the encryption step in the reconciler. A takeover of a same-named
user-created registry now clears any credentials it had stored.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] - Add ability for admins to set OCI Registry for all users

2 participants