Skip to content

First contribution to the rust-oci-client Nodejs Bindings - #1

Open
davidfestal wants to merge 29 commits into
oras-project:mainfrom
davidfestal:first-contribution
Open

First contribution to the rust-oci-client Nodejs Bindings#1
davidfestal wants to merge 29 commits into
oras-project:mainfrom
davidfestal:first-contribution

Conversation

@davidfestal

@davidfestal davidfestal commented Sep 2, 2026

Copy link
Copy Markdown

Node.js bindings for rust-oci-client

This PR bootstraps the rust-oci-client-node repository with full-featured Node.js bindings for rust-oci-client, as proposed in oras-project/community#81.

The bindings are implemented via NAPI-RS and expose the Rust oci-client crate to JavaScript/TypeScript consumers as the @oras-project/oci-client npm package.

Note: Since it is the bootstrapping PR that also brings CI workflow definitions, the CI check runs for this PR can be found in the PR fork branch.

What this brings

  • OCI Distribution client for Node.js — pull/push manifests, blobs, tags, referrers, and image indexes, with multi-platform resolution built in.
  • Structured OCI error types surfaced to JavaScript (ServerError, UnauthorizedError, AuthenticationFailure, …) with full cause chains.
  • Complete ClientConfig — TLS backends (native-tls / rustls), custom CA certificates, protocol selection, platform defaults.
  • File-based blob pull/push for large artifacts without buffering into memory.
  • Pre-built binaries for x86_64 and aarch64 on Linux (glibc + musl), macOS, Windows, plus s390x and ppc64le Linux.
  • TypeScript type definitions auto-generated from the Rust source.

Testing

  • A companion @oras-project/oci-client-testing workspace package provides a MockRegistry (in-process HTTP server) and a ZotRegistry helper (container-based) for integration tests.
  • 83 tests covering pull/push workflows, multi-arch images, referrers, blob mounts, digest-mismatch error paths, auth validation, and TLS configuration.

CI

  • GitHub Actions workflow: build matrix across all supported targets, test on Linux/macOS/Windows (Node 22 & 24), Zot integration tests, s390x via QEMU system emulation.
  • cargo-deny for license/advisory auditing, oxlint + clippy for linting, oxfmt + cargo fmt for formatting.

Governance

  • CONTRIBUTING.md and CODEOWNERS included.

Introduces Node.js bindings for the rust-oci-client using napi-rs,
enabling Node.js applications to interact with OCI registries.

Features:
- 17 OciClient methods: pull, push, manifests, blobs, tags, referrers
- Authentication helpers: anonymous, basic, bearer
- Platform resolver configuration via os/arch/variant filter
- Full TypeScript definitions auto-generated

Supported platforms (7 targets):
- macOS x86_64 and ARM64
- Linux x86_64 and ARM64 (glibc)
- Linux x86_64 and ARM64 (musl/Alpine)
- Windows x86_64

CI/CD:
- Build and test workflows for all platforms
- Publish workflow for npm releases
- Node.js 22 and 24 support
- Integration tests with Zot registry

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Signed-off-by: David Festal <dfestal@redhat.com>
…ndency changes, after review comments.

Signed-off-by: David Festal <dfestal@redhat.com>
... to allow safe release of resources and prevent further operations.

Use `parking_lot` mutex for interior mutability.
Update tests to verify client closure behavior.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
…pulling image manifests with list digest.

- Implemented the `/v2/_catalog` endpoint in the mock registry to list repositories with pagination support.
- Added methods in `OciClient` to pull image manifests and their associated list digests, enhancing multi-architecture image handling.
- Updated tests to verify the new functionality for catalog listing and manifest retrieval.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
- Introduced TLS capabilities in the mock registry using dynamically generated self-signed certificates.
- Updated tests to validate TLS connections, including scenarios for valid certificates, invalid certificates, and enforced CA certificate requirements.
- Added a new dependency on the `selfsigned` package for certificate generation.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Add s390x-unknown-linux-gnu and powerpc64le-unknown-linux-gnu to the
napi cross-compilation target list in package.json.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
… errors

Change `OciClient.withConfig` to return a `Result` and use `Client::try_from`
to validate the native client configuration, so malformed certificates or
bad proxy URLs throw explicit errors instead of being silently ignored.

Update the Node.js binding tests to use dynamically generated TLS
certificates for the custom certificate cases and add a test verifying
that invalid PEM data is rejected.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
… author

Signed-off-by: David Festal <dfestal@redhat.com>
Add a contributing guide covering DCO sign-off, PR review requirements,
and the CNCF Code of Conduct. Introduce a CODEOWNERS file and update the
README contributing link to reference the local file.

Signed-off-by: David Festal <dfestal@redhat.com>
Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
…n errors

Centralize OCI reference parsing in a single helper to reduce duplication
and ensure invalid reference errors include the offending value.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
… policy

Introduce `deny.toml` to enforce allowed licenses, clarify `encoding_rs`
and `ring` licenses, and ignore specific RustSec advisories. Add a daily
security audit workflow and run `cargo-deny` plus `cargo fmt`/`clippy`
checks in the Node.js build workflow. Also add `deny.toml` to the
workflow path triggers and implement `Default` for `OciClient`.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
…lls, and verified assets

Add `contents: read` permissions to workflows, switch all `yarn install` commands to `--immutable`, and verify s390x Ubuntu cloud image downloads via GPG signatures and SHA256 checksums. Pin the s390x Node.js tarball and the ZOT test registry image by digest, and extract the s390x VM init script to `.github/scripts/s390x-init.sh`.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
…mock certs and tests for rustls compatibility

Add a README section explaining why `native-tls` is the default for cross-compiled prebuilt binaries and how to build from source with `rustls-tls`. Harden the `accept_invalid_certificates` Rust doc comment with a security warning. Update the mock registry to generate non-CA, sha256 server certificates and relax the invalid-certificate test so it passes under both TLS backends.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Signed-off-by: David Festal <dfestal@redhat.com>
Pin the `cargo-zigbuild` installation in the Node.js build workflow to
`cargo-zigbuild@0.23.0` for reproducible cross-compilation builds.

Signed-off-by: David Festal <dfestal@redhat.com>
Add `src/error.rs` with a `#[napi(discriminant = "type")]` `OciClientError` enum that maps every `OciDistributionError` variant to a typed, serializable JS error. Convert async binding methods to use `AsyncBlockBuilder::build_with_map` so thrown `Error` objects carry a `type` tag and variant-specific fields (`statusCode`, `url`, `errors`, `image`, etc.). Add `fromOciError` to normalize arbitrary errors into the discriminated union.

Enable `napi`'s `serde-json` feature and add `serde`/`serde_json` dependencies. Extend the mock registry with error-triggering endpoints and add TypeScript tests covering structured error round-tripping.

Assisted-by: Cursor
Assisted-by: Gemini
Signed-off-by: David Festal <dfestal@redhat.com>
Add `oxfmt` as a dev dependency and introduce a `format` script in `package.json`.

Signed-off-by: David Festal <dfestal@redhat.com>
Signed-off-by: David Festal <dfestal@redhat.com>
Load `manifest.json` in the mock registry and update its embedded config
and layer digests/sizes to match the actual in-memory fixture bytes,
ensuring consistent digest calculations across tests.

Assisted-by: Gemini
Signed-off-by: David Festal <dfestal@redhat.com>
Use `bytes::Bytes::from_owner` to take ownership of NAPI `Buffer`s instead
of `to_vec`, converting `to_native` into `into_native`. Add the `bytes`
crate dependency and document the borrow-until-Promise-settles contract
in the README and Rust doc comments.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Add `pullBlobToFile` and `pushBlobFromFile` methods that stream blobs
between the registry and the local filesystem without buffering them
in JavaScript `Buffer`s. Pull writes directly to a created/truncated
file and verifies the digest; push reads a file via `ReaderStream` and
streams it to the registry.

Add `futures-util` and `tokio-util` dependencies, document the new
APIs in the README, and add mock/Zot registry tests covering happy
paths and I/O error cases.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
…ethods

Document the distinction between methods that accept an explicit `auth`
parameter and internally store credentials and methods that rely on
previously stored credentials. Update the `storeAuth` README entry and
Rust doc comments to explain the `store_auth_if_needed` behavior.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
Signed-off-by: David Festal <dfestal@redhat.com>
… and blob mounts

Add `__test__/helpers.ts` with `pushPlatformImage` and `pushMultiarchImage`
to reduce duplication when building multi-arch images in Zot tests.

Add tests for `pullManifestRaw`, `pullReferrers`, and `mountBlob`, and
refactor existing multi-arch round-trip and platform-filter tests to use
the new helper.

Extend the mock registry with an OCI referrers endpoint and mark the
`testing` package as ESM so helper imports resolve correctly.

Assisted-by: Cursor
Signed-off-by: David Festal <dfestal@redhat.com>
@davidfestal davidfestal changed the title First contribution of the Nodejs Bindings First contribution to the rust-oci-client Nodejs Bindings Sep 2, 2026
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.

1 participant