Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ jobs:
run: go test ./internal/...

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v9
with:
version: latest
12 changes: 9 additions & 3 deletions internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Config struct {
Env Environment
Volumes []string
DockerfilePath string
Network string
}

type GitUserConfig struct {
Expand Down Expand Up @@ -67,14 +68,18 @@ func ParseConfig(args []string, environment []string) Config {
}
}

var additionalEnv stringSlice
var volumes stringSlice
var dockerfilePath string
var (
additionalEnv stringSlice
volumes stringSlice
dockerfilePath string
network string
)

fs := flag.NewFlagSet("contagent", flag.ContinueOnError)
fs.Var(&additionalEnv, "env", "environment variable")
fs.Var(&volumes, "volume", "volume mount")
fs.StringVar(&dockerfilePath, "dockerfile", "", "Dockerfile path")
fs.StringVar(&network, "network", "default", " Connect to a container network")

// Ignore errors since we want to capture remaining args
_ = fs.Parse(args)
Expand Down Expand Up @@ -123,5 +128,6 @@ func ParseConfig(args []string, environment []string) Config {
Args: Command(programArgs),
Env: Environment(env),
Volumes: allVolumes,
Network: network,
}
}
14 changes: 14 additions & 0 deletions internal/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func TestConfig(t *testing.T) {
"ANTHROPIC_API_KEY=some-api-key",
"SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock",
}), config.Env)
require.Equal(t, "default", config.Network)
})

t.Run("with --env flags", func(t *testing.T) {
Expand Down Expand Up @@ -125,5 +126,18 @@ func TestConfig(t *testing.T) {
config := internal.ParseConfig(args, env)
require.Equal(t, "/some/path/to/a/Dockerfile", config.DockerfilePath)
})

t.Run("when given a --network flag", func(t *testing.T) {
args := []string{
"--network", "some-network",
"some-program",
}
env := []string{
"TERM=some-term",
}

config := internal.ParseConfig(args, env)
require.Equal(t, "some-network", config.Network)
})
})
}
5 changes: 3 additions & 2 deletions internal/docker/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (c Client) BuildImage(ctx context.Context, dockerfilePath string, imageName
// It configures the container with TTY support, stdin attachment, environment variables,
// working directory, volume mounts, and network settings to allow communication with the host
// via host.docker.internal. Returns a Container handle or an error if creation fails.
func (c Client) CreateContainer(ctx context.Context, sessionID internal.SessionID, image Image, args internal.Command, env internal.Environment, volumes []string, workingDir string, stopTimeout, ttyRetries int, retryDelay time.Duration) (Container, error) {
func (c Client) CreateContainer(ctx context.Context, sessionID internal.SessionID, image Image, args internal.Command, env internal.Environment, volumes []string, workingDir, network string, stopTimeout, ttyRetries int, retryDelay time.Duration) (Container, error) {
response, err := c.client.ContainerCreate(ctx, client.ContainerCreateOptions{
Config: &container.Config{
Image: image.Name,
Expand All @@ -158,7 +158,8 @@ func (c Client) CreateContainer(ctx context.Context, sessionID internal.SessionI
ExtraHosts: []string{
"host.docker.internal:host-gateway",
},
Binds: volumes,
Binds: volumes,
NetworkMode: container.NetworkMode(network),
},
Name: string(sessionID),
NetworkingConfig: nil,
Expand Down
6 changes: 3 additions & 3 deletions internal/docker/client_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func TestCreateContainerWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test-container", image, []string{"echo", "test"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test-container", image, []string{"echo", "test"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)
assert.Equal(t, "container123", container.ID)
assert.Equal(t, "test-container", container.Name)
Expand All @@ -172,7 +172,7 @@ func TestCreateContainerWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "nonexistent:latest"}

_, err := c.CreateContainer(ctx, "test-container", image, []string{"echo", "test"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
_, err := c.CreateContainer(ctx, "test-container", image, []string{"echo", "test"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to create container")
})
Expand All @@ -195,7 +195,7 @@ func TestCreateContainerWithMock(t *testing.T) {
volumes := []string{"/host:/container"}
workingDir := "/custom"

_, err := c.CreateContainer(ctx, "test-name", image, args, env, volumes, workingDir, 10, 10, 100*time.Millisecond)
_, err := c.CreateContainer(ctx, "test-name", image, args, env, volumes, workingDir, "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

assert.Equal(t, "alpine:latest", capturedOptions.Config.Image)
Expand Down
22 changes: 11 additions & 11 deletions internal/docker/container_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestContainerStartWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.Start(ctx)
Expand All @@ -55,7 +55,7 @@ func TestContainerStartWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.Start(ctx)
Expand Down Expand Up @@ -84,7 +84,7 @@ func TestContainerRemoveWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.Remove(ctx)
Expand All @@ -106,7 +106,7 @@ func TestContainerRemoveWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.Remove(ctx)
Expand Down Expand Up @@ -135,7 +135,7 @@ func TestContainerForceRemoveWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.ForceRemove(ctx)
Expand All @@ -157,7 +157,7 @@ func TestContainerForceRemoveWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.ForceRemove(ctx)
Expand Down Expand Up @@ -186,7 +186,7 @@ func TestContainerCopyToWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.CopyTo(ctx, io.NopCloser(nil), "/tmp")
Expand All @@ -208,7 +208,7 @@ func TestContainerCopyToWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

err = container.CopyTo(ctx, io.NopCloser(nil), "/tmp")
Expand Down Expand Up @@ -239,7 +239,7 @@ func TestContainerWaitWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

writer := newMockWriter()
Expand All @@ -265,7 +265,7 @@ func TestContainerWaitWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"sh", "-c", "exit 42"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"sh", "-c", "exit 42"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

writer := newMockWriter()
Expand All @@ -291,7 +291,7 @@ func TestContainerWaitWithMock(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

writer := newMockWriter()
Expand Down
2 changes: 1 addition & 1 deletion internal/docker/tty_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func TestContainerResizeIntegration(t *testing.T) {
ctx := context.Background()
image := docker.Image{Name: "alpine:latest"}

container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", 10, 10, 100*time.Millisecond)
container, err := c.CreateContainer(ctx, "test", image, []string{"echo"}, []string{}, []string{}, "/app", "some-network", 10, 10, 100*time.Millisecond)
require.NoError(t, err)

writer := newMockWriter()
Expand Down
25 changes: 0 additions & 25 deletions internal/git/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,6 @@ func TestGitServerErrorCases(t *testing.T) {
require.Error(t, err)
})

t.Run("directory with permission denied", func(t *testing.T) {
if os.Getuid() == 0 {
t.Skip("Running as root, cannot test permission denied")
}

dir, err := os.MkdirTemp("", "git-perm-test")
require.NoError(t, err)
defer os.RemoveAll(dir)

// Initialize git repo
cmd := exec.Command("git", "init")
cmd.Dir = dir
require.NoError(t, cmd.Run())

// Remove permissions
err = os.Chmod(dir, 0000)
require.NoError(t, err)

// Restore permissions for cleanup
defer os.Chmod(dir, 0755)

_, err = git.NewServer(dir, internal.NewStandardWriter())
require.Error(t, err)
})

t.Run("relative path resolution", func(t *testing.T) {
dir, err := os.MkdirTemp("", "git-rel-test")
require.NoError(t, err)
Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ func run(args, env []string) error {
config.Env,
config.Volumes,
config.WorkingDir,
config.Network,
config.StopTimeout,
config.TTYRetries,
config.RetryDelay,
Expand Down
Loading