Skip to content

Spike: unified Remote interface over nebi server and OCI registry - #556

Draft
tylerpotts wants to merge 2 commits into
mainfrom
spike/remote-interface
Draft

Spike: unified Remote interface over nebi server and OCI registry#556
tylerpotts wants to merge 2 commits into
mainfrom
spike/remote-interface

Conversation

@tylerpotts

Copy link
Copy Markdown
Collaborator

Exploration for #555: can one Remote interface make nebi servers and OCI registries peers from a client's point of view?

Verdict: yes, with adjustments. The proposed interface holds up once versions become string refs instead of uint, methods take a context.Context, and pull gains version addressing. Full findings in internal/remote/README.md.

What this adds

A self-contained spike package, internal/remote, alongside the existing code (nothing else is touched):

  • remote.go — the Remote interface, credential types, and typed error sentinels (ErrNotAuthenticated, ErrUnauthorized, ErrForbidden, ErrNotFound, ErrConflict)
  • oci.goOCIRemote, wrapping internal/oci/oras
  • server.goServerRemote, wrapping internal/cliclient
  • conformance_test.go — one shared lifecycle script: discover auth schemes, reject bad credentials, authenticate, push a new workspace, list, pull latest and by ref, push conflict, push v2, typed not-found errors
  • README.md — the exploration report

Demonstration

The same conformance script passes unmodified against both backends:

go test ./internal/remote/            # OCIRemote vs in-memory Distribution registry (basic-auth + anonymous)
go test -tags e2e ./internal/remote/  # ServerRemote vs real in-process team-mode nebi server (+ token auth)

Key findings (details in the README)

  • internal/oci has no typed errors; mapping works only because oras errors survive the %w chains
  • oci.ListRepositories/ListTags never set PlainHTTP, so they can't reach plain-HTTP registries at all (bug worth fixing independently)
  • OCI conflict detection is read-before-write (racy); the server's is atomic
  • Server workspace creation is async, so push-to-new hides a pending→ready poll behind a synchronous signature
  • The server returns 403 for unknown workspace IDs (RBAC before existence), so ErrNotFound can't be promised uniformly
  • SupportedAuthentication is discovery on the server but can only be configuration for OCI; OIDC device flow composes with the interface but can't live inside AuthenticationCredential
  • Open modeling question: assets (OCI bundles carry arbitrary files; the server push/pull API moves only pixi.toml/pixi.lock)

Deliberately out of scope: wiring into cmd/nebi or /remote/* handlers, nebi-repo filtering in OCI List, Quay token auth, asset transfer.

Exploratory work for making servers and OCI registries peers. Adds
internal/remote with the proposed Remote interface, OCIRemote and
ServerRemote implementations, a shared conformance test that passes
against both backends, and README.md with findings.
Comment thread internal/remote/server.go
// The server additionally supports an OIDC device flow (probed via
// GET /auth/device-config); that cannot be expressed as a static
// credential and is out of scope for the spike (see README).
return []AuthenticationCredentialType{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylerpotts Can you include the device flow in the scope? Maybe we need to split between static and "dynamic" auth.

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.

2 participants