Skip to content

Commit 223351d

Browse files
committed
fix: build registry auth and Docker image OCI compatibility
- Add 10.100.x.x subnet to allowed VM networks for registry auth fallback (remote servers use 10.100.x.x while IP fallback only allowed 10.102.x.x) - Convert Docker v2 mediatypes to OCI equivalents in image unpacking (umoci requires OCI mediatypes but Docker Hub images use Docker mediatypes) - Explicitly set DOCKER_CONFIG env var for buildctl to ensure it finds auth config - Update documentation to use docker buildx with oci-mediatypes=true
1 parent e77731d commit 223351d

File tree

5 files changed

+48
-36
lines changed

5 files changed

+48
-36
lines changed

lib/builds/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,13 @@ Builder images must include:
273273
See [`images/README.md`](./images/README.md) for detailed build instructions.
274274

275275
```bash
276-
# Build and push the builder image
277-
docker build \
278-
-t yourregistry/builder:latest \
276+
# Build and push the builder image (must use OCI mediatypes)
277+
docker buildx build \
278+
--platform linux/amd64 \
279+
--output type=image,oci-mediatypes=true,push=true \
280+
--tag yourregistry/builder:latest \
279281
-f lib/builds/images/generic/Dockerfile \
280282
.
281-
282-
docker push yourregistry/builder:latest
283283
```
284284

285285
### Environment Variables
@@ -366,7 +366,7 @@ go test ./lib/builds/registry_token_test.go ./lib/builds/registry_token.go -v
366366
curl -X POST http://localhost:8083/images \
367367
-H "Authorization: Bearer $TOKEN" \
368368
-H "Content-Type: application/json" \
369-
-d '{"name": "hirokernel/builder-generic:latest"}'
369+
-d '{"name": "onkernel/builder-generic:latest"}'
370370
```
371371

372372
3. **Create test source with Dockerfile**:

lib/builds/builder_agent/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,10 @@ func runBuild(ctx context.Context, config *BuildConfig, logWriter io.Writer) (st
572572
cmd.Stdout = io.MultiWriter(logWriter, &buildLogs)
573573
cmd.Stderr = io.MultiWriter(logWriter, &buildLogs)
574574
// Use BUILDKITD_FLAGS from environment (set in Dockerfile) or empty for default
575-
cmd.Env = os.Environ()
575+
// Explicitly set DOCKER_CONFIG to ensure buildkit finds the auth config
576+
env := os.Environ()
577+
env = append(env, "DOCKER_CONFIG=/home/builder/.docker")
578+
cmd.Env = env
576579

577580
if err := cmd.Run(); err != nil {
578581
return "", buildLogs.String(), fmt.Errorf("buildctl failed: %w", err)

lib/builds/images/README.md

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ images/
4444

4545
## Building the Generic Builder Image
4646

47-
Hypeman supports both Docker v2 and OCI image formats. You can use standard `docker build`
48-
or `docker buildx` - both work.
47+
Hypeman requires images to use **OCI mediatypes**. Use `docker buildx` with `oci-mediatypes=true`
48+
to ensure compatibility.
4949

5050
### Prerequisites
5151

52-
1. **Docker** installed
52+
1. **Docker** with buildx installed
5353
2. **Docker Hub login** (or your registry):
5454
```bash
5555
docker login
@@ -58,22 +58,11 @@ or `docker buildx` - both work.
5858
### 1. Build and Push
5959

6060
```bash
61-
# From repository root
62-
docker build \
63-
-t hirokernel/builder-generic:latest \
64-
-f lib/builds/images/generic/Dockerfile \
65-
.
66-
67-
docker push hirokernel/builder-generic:latest
68-
```
69-
70-
Or with buildx for multi-platform support:
71-
72-
```bash
61+
# From repository root - use buildx with OCI mediatypes
7362
docker buildx build \
7463
--platform linux/amd64 \
75-
--push \
76-
--tag hirokernel/builder-generic:latest \
64+
--output type=image,oci-mediatypes=true,push=true \
65+
--tag onkernel/builder-generic:latest \
7766
-f lib/builds/images/generic/Dockerfile \
7867
.
7968
```
@@ -88,10 +77,10 @@ TOKEN=$(make gen-jwt | tail -1)
8877
curl -X POST http://localhost:8083/images \
8978
-H "Authorization: Bearer $TOKEN" \
9079
-H "Content-Type: application/json" \
91-
-d '{"name": "hirokernel/builder-generic:latest"}'
80+
-d '{"name": "onkernel/builder-generic:latest"}'
9281

9382
# Wait for import to complete
94-
curl http://localhost:8083/images/docker.io%2Fhirokernel%2Fbuilder-generic:latest \
83+
curl http://localhost:8083/images/docker.io%2Fonkernel%2Fbuilder-generic:latest \
9584
-H "Authorization: Bearer $TOKEN"
9685
```
9786

@@ -100,7 +89,7 @@ curl http://localhost:8083/images/docker.io%2Fhirokernel%2Fbuilder-generic:lates
10089
Set the builder image in your `.env`:
10190

10291
```bash
103-
BUILDER_IMAGE=hirokernel/builder-generic:latest
92+
BUILDER_IMAGE=onkernel/builder-generic:latest
10493
```
10594

10695
### Building for Local Testing (without pushing)
@@ -245,7 +234,7 @@ When the builder runs inside a Hypeman microVM:
245234

246235
```bash
247236
# Check image status
248-
cat ~/hypeman_data_dir/images/docker.io/hirokernel/builder-generic/*/metadata.json | jq .
237+
cat ~/hypeman_data_dir/images/docker.io/onkernel/builder-generic/*/metadata.json | jq .
249238

250239
# Check OCI cache index
251240
cat ~/hypeman_data_dir/system/oci-cache/index.json | jq '.manifests[-1]'

lib/images/oci.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -346,20 +346,21 @@ func (c *ociClient) unpackLayers(ctx context.Context, layoutTag, targetDir strin
346346
// convertToOCIManifest converts a go-containerregistry manifest to OCI v1.Manifest
347347
// This allows us to use go-containerregistry (which handles both Docker v2 and OCI v1)
348348
// for manifest parsing, while still using umoci for layer unpacking.
349+
// Docker v2 mediatypes are converted to OCI equivalents since umoci expects OCI format.
349350
func convertToOCIManifest(gcrManifest *gcr.Manifest) v1.Manifest {
350-
// Convert config descriptor
351+
// Convert config descriptor with mediatype conversion
351352
configDesc := v1.Descriptor{
352-
MediaType: string(gcrManifest.Config.MediaType),
353+
MediaType: convertToOCIMediaType(string(gcrManifest.Config.MediaType)),
353354
Digest: gcrDigestToOCI(gcrManifest.Config.Digest),
354355
Size: gcrManifest.Config.Size,
355356
Annotations: gcrManifest.Config.Annotations,
356357
}
357358

358-
// Convert layer descriptors
359+
// Convert layer descriptors with mediatype conversion
359360
layers := make([]v1.Descriptor, len(gcrManifest.Layers))
360361
for i, layer := range gcrManifest.Layers {
361362
layers[i] = v1.Descriptor{
362-
MediaType: string(layer.MediaType),
363+
MediaType: convertToOCIMediaType(string(layer.MediaType)),
363364
Digest: gcrDigestToOCI(layer.Digest),
364365
Size: layer.Size,
365366
Annotations: layer.Annotations,
@@ -370,13 +371,32 @@ func convertToOCIManifest(gcrManifest *gcr.Manifest) v1.Manifest {
370371
Versioned: specs.Versioned{
371372
SchemaVersion: int(gcrManifest.SchemaVersion),
372373
},
373-
MediaType: string(gcrManifest.MediaType),
374+
MediaType: convertToOCIMediaType(string(gcrManifest.MediaType)),
374375
Config: configDesc,
375376
Layers: layers,
376377
Annotations: gcrManifest.Annotations,
377378
}
378379
}
379380

381+
// convertToOCIMediaType converts Docker v2 media types to OCI equivalents.
382+
// Images from Docker Hub often use Docker-specific mediatypes, but umoci
383+
// requires OCI-standard mediatypes for layer unpacking.
384+
func convertToOCIMediaType(mediaType string) string {
385+
switch mediaType {
386+
case "application/vnd.docker.distribution.manifest.v2+json":
387+
return v1.MediaTypeImageManifest
388+
case "application/vnd.docker.container.image.v1+json":
389+
return v1.MediaTypeImageConfig
390+
case "application/vnd.docker.image.rootfs.diff.tar.gzip":
391+
return v1.MediaTypeImageLayerGzip
392+
case "application/vnd.docker.image.rootfs.diff.tar":
393+
return v1.MediaTypeImageLayer
394+
default:
395+
// If already OCI or unknown, return as-is
396+
return mediaType
397+
}
398+
}
399+
380400
// gcrDigestToOCI converts a go-containerregistry digest to OCI digest
381401
func gcrDigestToOCI(d gcr.Hash) digest.Digest {
382402
return digest.NewDigestFromEncoded(digest.Algorithm(d.Algorithm), d.Hex)

lib/middleware/oapi_auth.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ func isRegistryPath(path string) bool {
181181
return strings.HasPrefix(path, "/v2/")
182182
}
183183

184-
// isInternalVMRequest checks if the request is from an internal VM network (10.102.x.x)
184+
// isInternalVMRequest checks if the request is from an internal VM network
185185
// This is used as a fallback for builder VMs that don't have token auth yet.
186186
//
187187
// SECURITY: We only trust RemoteAddr, not X-Real-IP or X-Forwarded-For headers,
@@ -195,8 +195,8 @@ func isInternalVMRequest(r *http.Request) bool {
195195
ip = ip[:idx]
196196
}
197197

198-
// Check if it's from the VM network (10.102.x.x)
199-
return strings.HasPrefix(ip, "10.102.")
198+
// Check if it's from the VM network (10.100.x.x or 10.102.x.x)
199+
return strings.HasPrefix(ip, "10.100.") || strings.HasPrefix(ip, "10.102.")
200200
}
201201

202202
// extractRepoFromPath extracts the repository name from a registry path.

0 commit comments

Comments
 (0)