Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
58eac6d
Export images to rootfs with docker
sjmiller609 Nov 6, 2025
521917d
docker client dependency injection
sjmiller609 Nov 6, 2025
1b7b6a3
Fix permissions during extraction
sjmiller609 Nov 6, 2025
e0110bd
Don't skip docker in tests
sjmiller609 Nov 6, 2025
817a85c
extraction test passing but seems too complicated
sjmiller609 Nov 6, 2025
19e4c64
Use umoci for image to rootfs conversion
sjmiller609 Nov 7, 2025
3cf8089
Update docs
sjmiller609 Nov 7, 2025
2dcfde5
Update README
sjmiller609 Nov 7, 2025
9c79b18
Move OCI cache dir
sjmiller609 Nov 7, 2025
db95987
Tweak disk settings
sjmiller609 Nov 7, 2025
4e13b7c
Async API
sjmiller609 Nov 7, 2025
c376477
Simplify async API: remove sse for now
sjmiller609 Nov 7, 2025
0ee7646
Avoid rate limit in CI
sjmiller609 Nov 7, 2025
a12d4ba
Add API level image test
sjmiller609 Nov 7, 2025
5c5e07d
Check queuing works
sjmiller609 Nov 7, 2025
8bf8a4f
Test failure on invalid tag
sjmiller609 Nov 7, 2025
d39fdca
Fix image filesystem layout
sjmiller609 Nov 7, 2025
5fbacba
image name validation
sjmiller609 Nov 7, 2025
bc8a7e5
Update README
sjmiller609 Nov 7, 2025
6cc60a6
Clean up error
sjmiller609 Nov 10, 2025
675e090
Use erofs
sjmiller609 Nov 10, 2025
e68a49d
API layer depends on domain
sjmiller609 Nov 10, 2025
a5737ab
Idempotency and race conditions
sjmiller609 Nov 10, 2025
3e8e835
Add erofs to ci
sjmiller609 Nov 10, 2025
3c9fc0d
OCI client internal to image manager
sjmiller609 Nov 10, 2025
5fda8e9
Disambiguate digests and tags
sjmiller609 Nov 10, 2025
37fac0b
WIP: figuring out error handling registry errors
sjmiller609 Nov 10, 2025
d8bab8a
Switch to more lightweight library for interacting with registry
sjmiller609 Nov 10, 2025
0c0f38a
Handle 404
sjmiller609 Nov 10, 2025
8126152
Use docker auth config file
sjmiller609 Nov 10, 2025
866f855
Add timeout on resolve
sjmiller609 Nov 10, 2025
4001e3a
Update README
sjmiller609 Nov 10, 2025
28e2589
Poll by digest
sjmiller609 Nov 10, 2025
3b09260
Tweak readme
sjmiller609 Nov 10, 2025
55ccb76
caching test
sjmiller609 Nov 10, 2025
325b5e9
More comprehensive basic test
sjmiller609 Nov 10, 2025
ffd312a
gen jwt script
rgarcia Nov 11, 2025
01c295a
Merge branch 'main' into gen-jwt
rgarcia Nov 11, 2025
874486d
fix merge
rgarcia Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
JWT_SECRET='your-secret-key-here'
DATA_DIR=/home/your-user/hypeman/.datadir # or leave unset to default to /var/lib/hypeman
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ bin/**
.env
tmp
tmp/**
.datadir
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
SHELL := /bin/bash
.PHONY: oapi-generate generate-wire generate-all dev build test install-tools
.PHONY: oapi-generate generate-wire generate-all dev build test install-tools gen-jwt

# Directory where local binaries will be installed
BIN_DIR ?= $(CURDIR)/bin
Expand All @@ -11,6 +11,7 @@ $(BIN_DIR):
OAPI_CODEGEN ?= $(BIN_DIR)/oapi-codegen
AIR ?= $(BIN_DIR)/air
WIRE ?= $(BIN_DIR)/wire
GODOTENV ?= $(BIN_DIR)/godotenv

# Install oapi-codegen
$(OAPI_CODEGEN): | $(BIN_DIR)
Expand All @@ -24,7 +25,11 @@ $(AIR): | $(BIN_DIR)
$(WIRE): | $(BIN_DIR)
GOBIN=$(BIN_DIR) go install github.com/google/wire/cmd/wire@latest

install-tools: $(OAPI_CODEGEN) $(AIR) $(WIRE)
# Install godotenv for loading .env files
$(GODOTENV): | $(BIN_DIR)
GOBIN=$(BIN_DIR) go install github.com/joho/godotenv/cmd/godotenv@latest

install-tools: $(OAPI_CODEGEN) $(AIR) $(WIRE) $(GODOTENV)

# Generate Go code from OpenAPI spec
oapi-generate: $(OAPI_CODEGEN)
Expand Down Expand Up @@ -53,6 +58,11 @@ dev: $(AIR)
test:
go test -tags containers_image_openpgp -v -timeout 30s ./...

# Generate JWT token for testing
# Usage: make gen-jwt [USER_ID=test-user]
gen-jwt: $(GODOTENV)
@$(GODOTENV) -f .env go run ./cmd/gen-jwt -user-id $${USER_ID:-test-user}

# Clean generated files and binaries
clean:
rm -rf $(BIN_DIR)
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,18 @@ make build
```
### Running the Server

Start the server with hot-reload for development:
1. Copy the example environment file and modify the values:
```bash
cp .env.example .env
# Edit .env and set JWT_SECRET and other configuration values
```

2. Generate a JWT token for testing (optional):
```bash
make gen-jwt
```

3. Start the server with hot-reload for development:
```bash
make dev
```
Expand Down
4 changes: 2 additions & 2 deletions cmd/api/api/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ func (s *ApiService) ListImages(ctx context.Context, request oapi.ListImagesRequ
Message: "failed to list images",
}, nil
}

oapiImages := make([]oapi.Image, len(domainImages))
for i, img := range domainImages {
oapiImages[i] = imageToOAPI(img)
}

return oapi.ListImages200JSONResponse(oapiImages), nil
}

Expand Down
34 changes: 34 additions & 0 deletions cmd/gen-jwt/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"flag"
"fmt"
"os"
"time"

"github.com/golang-jwt/jwt/v5"
)

func main() {
jwtSecret := os.Getenv("JWT_SECRET")
if jwtSecret == "" {
fmt.Fprintf(os.Stderr, "Error: JWT_SECRET environment variable is not set\n")
os.Exit(1)
}
userID := flag.String("user-id", "test-user", "User ID to include in the JWT token")
flag.Parse()

claims := jwt.MapClaims{
"sub": *userID,
"iat": time.Now().Unix(),
"exp": time.Now().Add(24 * time.Hour).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(jwtSecret))
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating token: %v\n", err)
os.Exit(1)
}

fmt.Println(tokenString)
}
11 changes: 5 additions & 6 deletions lib/images/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/opencontainers/image-spec/specs-go/v1"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
rspec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/umoci/oci/cas/dir"
"github.com/opencontainers/umoci/oci/casext"
Expand Down Expand Up @@ -70,7 +70,7 @@ func (c *ociClient) inspectManifest(ctx context.Context, imageRef string) (strin

// Use system authentication (reads from ~/.docker/config.json, etc.)
// Default retry: only on network errors, max ~1.3s total
descriptor, err := remote.Head(ref,
descriptor, err := remote.Head(ref,
remote.WithContext(ctx),
remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
Expand Down Expand Up @@ -126,7 +126,7 @@ func (c *ociClient) pullToOCILayout(ctx context.Context, imageRef, layoutTag str

// Use system authentication (reads from ~/.docker/config.json, etc.)
// Default retry: only on network errors, max ~1.3s total
img, err := remote.Image(ref,
img, err := remote.Image(ref,
remote.WithContext(ctx),
remote.WithAuthFromKeychain(authn.DefaultKeychain))
if err != nil {
Expand Down Expand Up @@ -293,7 +293,7 @@ func (c *ociClient) unpackLayers(ctx context.Context, imageRef, targetDir string
// Map container UIDs to current user's UID (identity mapping)
uid := uint32(os.Getuid())
gid := uint32(os.Getgid())

unpackOpts := &layer.UnpackOptions{
OnDiskFormat: layer.DirRootfs{
MapOptions: layer.MapOptions{
Expand All @@ -307,7 +307,7 @@ func (c *ociClient) unpackLayers(ctx context.Context, imageRef, targetDir string
},
},
}

err = layer.UnpackRootfs(context.Background(), casEngine, targetDir, manifest, unpackOpts)
if err != nil {
return fmt.Errorf("unpack rootfs: %w", err)
Expand All @@ -322,4 +322,3 @@ type containerMetadata struct {
Env map[string]string
WorkingDir string
}

Loading