fix(ssh): use bare mock-agent name so the remote PATH resolves it
For SSH the agent runs on a remote host whose filesystem doesn't share paths with the kandev backend's, so the host-absolute mock-agent path configureMockAgent computes can't apply. Extend the bare-name branch in MockAgent.BuildCommand to include RuntimeSSH (the SSH e2e image already bakes mock-agent into /usr/local/bin) and drop the now-redundant SSH e2e bind-mount that worked around this by mirroring the host path into the container.
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/kandev/kandev/internal/agent/usage"
|
||||
"github.com/kandev/kandev/internal/agentruntime"
|
||||
"github.com/kandev/kandev/pkg/agent"
|
||||
)
|
||||
|
||||
@@ -139,12 +140,19 @@ func (a *MockAgent) BuildCommand(opts CommandOptions) Command {
|
||||
// has /usr/local/bin on PATH and container.go bind-mounts the
|
||||
// linux/amd64 mock-agent there, so the bare name resolves correctly.
|
||||
//
|
||||
// SSH is the same shape: the agent runs on a remote host whose
|
||||
// filesystem doesn't share paths with the kandev backend's, so the
|
||||
// host-absolute binary path can't apply. The SSH e2e image bakes
|
||||
// mock-agent at /usr/local/bin/mock-agent; production SSH expects
|
||||
// users to install agents into the remote's $PATH (real agents like
|
||||
// Claude use `npx` and never hit this branch).
|
||||
//
|
||||
// For host runtimes (standalone) we prefer the absolute host path
|
||||
// that configureMockAgent computed via os.Executable() — that's the
|
||||
// only way the host path works in dev mode (where the shell's $PATH
|
||||
// doesn't include apps/backend/bin). Fall back to the bare name when
|
||||
// no path is set: e2e fixtures prepend the kandev bin dir to PATH.
|
||||
if opts.Runtime.IsContainerized() {
|
||||
if opts.Runtime.IsContainerized() || opts.Runtime == agentruntime.RuntimeSSH {
|
||||
return Cmd(mockAgentDefaultID).Build()
|
||||
}
|
||||
binary := mockAgentDefaultID
|
||||
|
||||
@@ -36,11 +36,12 @@ func TestMockAgent_BuildCommand_NoResumeFlag(t *testing.T) {
|
||||
|
||||
// TestMockAgent_BuildCommand_ContainerizedUsesBareName pins the docker
|
||||
// branch of BuildCommand: when opts.Runtime is containerized (docker,
|
||||
// remote_docker, sprites), MockAgent must emit the bare binary name so
|
||||
// PATH lookup inside the container resolves to the bind-mounted
|
||||
// linux/amd64 mock-agent at /usr/local/bin. Regressing this would
|
||||
// cause docker e2e to fail with `exec: "<host-abs-path>": not found`,
|
||||
// which is exactly the bug commit `8518f65` fixed.
|
||||
// remote_docker, sprites) or SSH, MockAgent must emit the bare binary
|
||||
// name so PATH lookup on the remote resolves to the bind-mounted (or
|
||||
// pre-baked) linux/amd64 mock-agent at /usr/local/bin. Regressing this
|
||||
// would cause docker e2e to fail with `exec: "<host-abs-path>": not
|
||||
// found` (the bug commit `8518f65` fixed) and SSH e2e with the same
|
||||
// symptom on the remote host.
|
||||
func TestMockAgent_BuildCommand_ContainerizedUsesBareName(t *testing.T) {
|
||||
a := NewMockAgent()
|
||||
a.SetBinaryPath("/Users/dev/kandev/apps/backend/bin/mock-agent")
|
||||
@@ -48,6 +49,7 @@ func TestMockAgent_BuildCommand_ContainerizedUsesBareName(t *testing.T) {
|
||||
agentruntime.RuntimeDocker,
|
||||
agentruntime.RuntimeRemoteDocker,
|
||||
agentruntime.RuntimeSprites,
|
||||
agentruntime.RuntimeSSH,
|
||||
} {
|
||||
t.Run(string(rt), func(t *testing.T) {
|
||||
cmd := a.BuildCommand(CommandOptions{Runtime: rt})
|
||||
|
||||
@@ -53,20 +53,6 @@ export function startSSHServer(
|
||||
const publicKeyFile = `${identityFile}.pub`;
|
||||
generateKeypair(identityFile);
|
||||
|
||||
// kandev's orchestrator builds the agent command using KANDEV_MOCK_AGENT_LINUX_BINARY,
|
||||
// which is set to the *host* absolute path of mock-agent-linux-amd64.
|
||||
// Docker e2e gets away with using that path inside the container because
|
||||
// it bind-mounts the same host file at the same path; for SSH e2e we have
|
||||
// to do the equivalent — otherwise the kandev backend tells agentctl on
|
||||
// the remote to exec a path that doesn't exist there.
|
||||
const mockAgentHostPath = path.resolve(__dirname, "../../../backend/bin/mock-agent-linux-amd64");
|
||||
if (!fs.existsSync(mockAgentHostPath)) {
|
||||
throw new Error(
|
||||
`mock-agent-linux-amd64 not found at ${mockAgentHostPath}; ` +
|
||||
`build it with 'make -C apps/backend build-mock-agent-linux'.`,
|
||||
);
|
||||
}
|
||||
|
||||
// The container reads /authorized_keys on entry, so mount the public key
|
||||
// into that path read-only.
|
||||
removeContainerIfExists(containerName);
|
||||
@@ -96,8 +82,6 @@ export function startSSHServer(
|
||||
"-v",
|
||||
`${publicKeyFile}:/authorized_keys:ro`,
|
||||
"-v",
|
||||
`${mockAgentHostPath}:${mockAgentHostPath}:ro`,
|
||||
"-v",
|
||||
`${remoteHome}:/home/kandev/.kandev`,
|
||||
imageTag,
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user