Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dd167b8e0b |
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"git.wntrmute.dev/mc/mcp/internal/auth"
|
||||||
"git.wntrmute.dev/mc/mcp/internal/config"
|
"git.wntrmute.dev/mc/mcp/internal/config"
|
||||||
"git.wntrmute.dev/mc/mcp/internal/runtime"
|
"git.wntrmute.dev/mc/mcp/internal/runtime"
|
||||||
"git.wntrmute.dev/mc/mcp/internal/servicedef"
|
"git.wntrmute.dev/mc/mcp/internal/servicedef"
|
||||||
@@ -52,6 +53,17 @@ func buildServiceImages(ctx context.Context, cfg *config.CLIConfig, def *service
|
|||||||
|
|
||||||
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
||||||
|
|
||||||
|
// Auto-login to the registry using the CLI's stored MCIAS token.
|
||||||
|
// MCR accepts JWTs as passwords, so this works for both human and
|
||||||
|
// service account tokens. Failures are non-fatal — existing podman
|
||||||
|
// auth may suffice.
|
||||||
|
if token, err := auth.LoadToken(cfg.Auth.TokenPath); err == nil && token != "" {
|
||||||
|
registry := extractRegistry(def)
|
||||||
|
if registry != "" {
|
||||||
|
_ = rt.Login(ctx, registry, "mcp", token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for imageName, dockerfile := range def.Build.Images {
|
for imageName, dockerfile := range def.Build.Images {
|
||||||
if imageFilter != "" && imageName != imageFilter {
|
if imageFilter != "" && imageName != imageFilter {
|
||||||
continue
|
continue
|
||||||
@@ -96,6 +108,19 @@ func findImageRef(def *servicedef.ServiceDef, imageName string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extractRegistry returns the registry host from the first component's
|
||||||
|
// image reference (e.g., "mcr.svc.mcp.metacircular.net:8443" from
|
||||||
|
// "mcr.svc.mcp.metacircular.net:8443/mcq:v0.1.1"). Returns empty
|
||||||
|
// string if no slash is found.
|
||||||
|
func extractRegistry(def *servicedef.ServiceDef) string {
|
||||||
|
for _, c := range def.Components {
|
||||||
|
if i := strings.LastIndex(c.Image, "/"); i > 0 {
|
||||||
|
return c.Image[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// extractRepoName returns the repository name from an image reference.
|
// extractRepoName returns the repository name from an image reference.
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
@@ -124,6 +149,8 @@ func ensureImages(ctx context.Context, cfg *config.CLIConfig, def *servicedef.Se
|
|||||||
return nil // no build config, skip auto-build
|
return nil // no build config, skip auto-build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registryLoginDone := false
|
||||||
|
|
||||||
for _, c := range def.Components {
|
for _, c := range def.Components {
|
||||||
if component != "" && c.Name != component {
|
if component != "" && c.Name != component {
|
||||||
continue
|
continue
|
||||||
@@ -153,6 +180,17 @@ func ensureImages(ctx context.Context, cfg *config.CLIConfig, def *servicedef.Se
|
|||||||
|
|
||||||
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
sourceDir := filepath.Join(cfg.Build.Workspace, def.Path)
|
||||||
|
|
||||||
|
// Auto-login to registry before first push.
|
||||||
|
if !registryLoginDone {
|
||||||
|
if token, err := auth.LoadToken(cfg.Auth.TokenPath); err == nil && token != "" {
|
||||||
|
registry := extractRegistry(def)
|
||||||
|
if registry != "" {
|
||||||
|
_ = rt.Login(ctx, registry, "mcp", token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registryLoginDone = true
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Printf("image %s not found, building from %s\n", c.Image, dockerfile)
|
fmt.Printf("image %s not found, building from %s\n", c.Image, dockerfile)
|
||||||
if err := rt.Build(ctx, c.Image, sourceDir, dockerfile); err != nil {
|
if err := rt.Build(ctx, c.Image, sourceDir, dockerfile); err != nil {
|
||||||
return fmt.Errorf("auto-build %s: %w", c.Image, err)
|
return fmt.Errorf("auto-build %s: %w", c.Image, err)
|
||||||
|
|||||||
@@ -178,6 +178,18 @@ func (p *Podman) Inspect(ctx context.Context, name string) (ContainerInfo, error
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Login authenticates to a container registry using the given token as
|
||||||
|
// the password. This enables non-interactive push with service account
|
||||||
|
// tokens (MCR accepts MCIAS JWTs as passwords).
|
||||||
|
func (p *Podman) Login(ctx context.Context, registry, username, token string) error {
|
||||||
|
cmd := exec.CommandContext(ctx, p.command(), "login", "--username", username, "--password-stdin", registry) //nolint:gosec // args built programmatically
|
||||||
|
cmd.Stdin = strings.NewReader(token)
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("podman login %q: %w: %s", registry, err, out)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Build builds a container image from a Dockerfile.
|
// Build builds a container image from a Dockerfile.
|
||||||
func (p *Podman) Build(ctx context.Context, image, contextDir, dockerfile string) error {
|
func (p *Podman) Build(ctx context.Context, image, contextDir, dockerfile string) error {
|
||||||
args := []string{"build", "-t", image, "-f", dockerfile, contextDir}
|
args := []string{"build", "-t", image, "-f", dockerfile, contextDir}
|
||||||
|
|||||||
Reference in New Issue
Block a user