Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 13 additions & 2 deletions wanda/forge.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,25 @@ func NewForge(config *ForgeConfig) (*Forge, error) {
return nil, fmt.Errorf("abs path for work dir: %w", err)
}

targetOS := runtime.GOOS
targetArch := runtime.GOARCH
if config.Platform != "" {
parts := strings.SplitN(config.Platform, "/", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return nil, fmt.Errorf("invalid platform format: %q, expected \"os/arch\"", config.Platform)
}
targetOS = parts[0]
targetArch = parts[1]
}
Comment on lines 60 to 67
Copy link
Contributor

Choose a reason for hiding this comment

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

high

The current platform string parsing is not robust. It silently ignores malformed platform strings (e.g., "linux") by falling back to the host's platform, and can mis-parse strings like "/arm64" or "linux/". This could lead to unexpected behavior. It would be better to validate the format and return an error for invalid input.

Suggested change
if config.Platform != "" {
parts := strings.SplitN(config.Platform, "/", 2)
if len(parts) == 2 {
targetOS = parts[0]
targetArch = parts[1]
}
}
if config.Platform != "" {
parts := strings.SplitN(config.Platform, "/", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return nil, fmt.Errorf("invalid platform format: %q, expected \"os/arch\"", config.Platform)
}
targetOS = parts[0]
targetArch = parts[1]
}


f := &Forge{
config: config,
workDir: absWorkDir,
remoteOpts: []remote.Option{
remote.WithAuthFromKeychain(authn.DefaultKeychain),
remote.WithPlatform(crane.Platform{
OS: runtime.GOOS,
Architecture: runtime.GOARCH,
OS: targetOS,
Architecture: targetArch,
}),
},
}
Expand Down
4 changes: 4 additions & 0 deletions wanda/forge_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ type ForgeConfig struct {
BuildID string
Epoch string

// Platform specifies the target platform for image resolution (e.g., "linux/arm64").
// If empty, defaults to the host OS/arch.
Platform string

RayCI bool
Rebuild bool

Expand Down
79 changes: 79 additions & 0 deletions wanda/forge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/http/httptest"
"os"
"runtime"
"strings"

"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/registry"
Expand Down Expand Up @@ -61,6 +62,84 @@ func filesInLayer(layer cranev1.Layer) (map[string]string, error) {

const worldDotTxt = "This is my world!"

func TestNewForge_Platform(t *testing.T) {
tests := []struct {
name string
platform string
wantErr bool
errContains string
}{
{
name: "empty platform uses defaults",
platform: "",
wantErr: false,
},
{
name: "valid linux/amd64",
platform: "linux/amd64",
wantErr: false,
},
{
name: "valid linux/arm64",
platform: "linux/arm64",
wantErr: false,
},
{
name: "invalid format - no slash",
platform: "linuxamd64",
wantErr: true,
errContains: "invalid platform format",
},
{
name: "invalid format - empty os",
platform: "/amd64",
wantErr: true,
errContains: "invalid platform format",
},
{
name: "invalid format - empty arch",
platform: "linux/",
wantErr: true,
errContains: "invalid platform format",
},
{
name: "invalid format - only slash",
platform: "/",
wantErr: true,
errContains: "invalid platform format",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config := &ForgeConfig{
WorkDir: "testdata",
Platform: tt.platform,
}

forge, err := NewForge(config)
if tt.wantErr {
if err == nil {
t.Errorf("got nil error, want error containing %q", tt.errContains)
return
}
if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) {
t.Errorf("got error %q, want error containing %q", err.Error(), tt.errContains)
}
return
}

if err != nil {
t.Fatalf("got error %v, want nil", err)
}

if forge == nil {
t.Error("got nil forge, want non-nil")
}
})
}
}

func TestForgeLocal_noNamePrefix(t *testing.T) {
config := &ForgeConfig{WorkDir: "testdata"}

Expand Down
7 changes: 7 additions & 0 deletions wanda/wanda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Flags:
func main() {
workDir := flag.String("work_dir", ".", "root directory for the build")
docker := flag.String("docker", "", "path to the docker client binary")
platform := flag.String("platform", "", "target platform for image resolution (e.g., linux/arm64)")
rayCI := flag.Bool(
"rayci", false,
"takes RAYCI_ env vars for input and run in remote mode",
Expand Down Expand Up @@ -71,13 +72,19 @@ func main() {
input = os.Getenv("RAYCI_WANDA_FILE")
}

targetPlatform := *platform
if targetPlatform == "" {
targetPlatform = os.Getenv("WANDA_PLATFORM")
}

config := &wanda.ForgeConfig{
WorkDir: *workDir,
DockerBin: *docker,
WorkRepo: *workRepo,
NamePrefix: *namePrefix,
BuildID: *buildID,
Epoch: *epoch,
Platform: targetPlatform,

RayCI: *rayCI,
Rebuild: *rebuild,
Expand Down