Skip to content

Add push SDK for uploading container images to OCI registry#8

Merged
rgarcia merged 7 commits intonextfrom
hypeship/add-push-sdk
Mar 28, 2026
Merged

Add push SDK for uploading container images to OCI registry#8
rgarcia merged 7 commits intonextfrom
hypeship/add-push-sdk

Conversation

@rgarcia
Copy link
Copy Markdown
Contributor

@rgarcia rgarcia commented Mar 28, 2026

Summary

Ports the push functionality from hypeman-go/lib/push.go to TypeScript, following the same patterns established by cp.ts.

Exported API

  • pushImage(cfg, image, targetName) — Push any OciImageSource to the hypeman OCI registry. Core function analogous to Go's PushImage().
  • push(cfg, sourceImage, targetName?) — Convenience: load from local Docker daemon and push. Analogous to Go's Push().
  • pushFromURL(baseURL, apiKey, image, targetName) — Convenience with raw URL/apiKey instead of config object. Analogous to Go's PushFromURL().
  • loadDockerImage(imageRef) — Load an image from the Docker daemon via docker save, returning an OciImageSource.
  • OciImageSource interface — Abstraction for container images from any source (Docker daemon, custom builds, etc.).

Implementation details

  • Uses OCI Distribution Spec for blob/manifest uploads (HEAD check, POST upload initiation, PUT blob, PUT manifest)
  • JWT bearer auth matching the Go implementation
  • Minimal tar parser for docker save output (no external tar dependency)
  • Layers from Docker are gzipped before push (docker save outputs uncompressed layers)
  • Re-exported from src/lib/index.ts barrel, importable as @onkernel/hypeman/lib/push

Differences from Go

  • PushConfig uses baseURL (like CpConfig in TS) instead of registryHost — more consistent with the TS SDK pattern where users construct configs directly
  • No ExtractPushConfig — the TS SDK doesn't use the request options extraction pattern
  • OciImageSource interface replaces Go's v1.Image — lightweight interface, no dependency on go-containerregistry equivalent
  • Uses child_process.spawn for docker save instead of Docker daemon API directly

Test plan

  • Verify TypeScript compilation passes (tsc --noEmit)
  • Test push() with a local Docker image against a hypeman registry
  • Test pushImage() with a custom OciImageSource
  • Test loadDockerImage() parses multi-layer images correctly
  • Verify blob deduplication (existing blobs are skipped via HEAD check)

Note

Medium Risk
Adds new container image push functionality that performs authenticated HTTP uploads and parses docker save archives, which could impact users via network/protocol edge cases and large payload handling.

Overview
Adds a new lib/push module that can upload container images to Hypeman’s OCI registry, including helpers to derive PushConfig from a client, push an arbitrary OciImageSource, and load/push images from the local Docker daemon.

Implements the OCI Distribution upload flow (blob existence checks, blob uploads, and manifest publishing) and introduces accompanying Jest coverage for config extraction, reference parsing, and upload request behavior; also re-exports the new API from src/lib/index.ts and adds required dependencies (dockerode, tar-stream).

Written by Cursor Bugbot for commit 01ffee7. This will update automatically on new commits. Configure here.

rgarcia and others added 7 commits March 28, 2026 16:15
Ports the push functionality from hypeman-go/lib/push.go to TypeScript,
following the same patterns established by cp.ts. Provides:

- pushImage(): Push any OciImageSource to the registry
- push(): Convenience to load from Docker daemon and push
- pushFromURL(): Convenience with raw URL/apiKey
- loadDockerImage(): Load image from local Docker via docker save

Uses the OCI Distribution Spec for blob and manifest uploads with
JWT bearer auth matching the Go implementation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hand-rolled docker save shelling and tar parsing with proper
libraries:
- Use dockerode for Docker daemon interaction (image.get() streams the
  tar, equivalent to go-containerregistry's daemon.Image)
- Use tar-stream for parsing the docker save archive
- Add extractPushConfig() to match Go's ExtractPushConfig API
- Change PushConfig to use registryHost (matching Go) instead of baseURL

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- push.ts: import Docker from 'dockerode' and import * as tar from
  'tar-stream' at top level, remove getDockerode/getTarStream wrappers
- cp.ts: import WebSocket from 'ws' at top level, remove getWebSocket
  wrapper and its call sites

No bundling concerns for this SDK so lazy loading is unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unit tests cover extractPushConfig, image reference parsing, blob upload
flow (auth headers, skip-existing, full upload sequence, error cases),
manifest content type, and pushFromURL. Integration tests are gated behind
HYPEMAN_INTEGRATION_TESTS=1 env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regenerate pnpm-lock.yaml to include dockerode and tar-stream deps.
Fix TS4111 errors by using bracket notation for process.env access.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Default to hypeman-test repo (matching scoped token claims).
Allow override via HYPEMAN_TEST_REPO env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rgarcia rgarcia marked this pull request as ready for review March 28, 2026 19:08
@rgarcia rgarcia merged commit ae2d717 into next Mar 28, 2026
7 checks passed
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