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
22 changes: 22 additions & 0 deletions go/agent/gitserver/softserve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package gitserver

import (
"context"
"runtime"
"testing"
"time"

Expand Down Expand Up @@ -47,8 +48,18 @@ func gitserverTestService(t *testing.T) (*softServe, Repository) {
return service, repositoryResult.Value.(Repository)
}

// gitserverRunGit runs one git command in directory and returns its trimmed
// combined output.
//
// core.autocrlf is pinned off for every invocation. Git for Windows turns it
// on by default, which rewrites LF to CRLF on checkout — the round-trip
// fixture pushed as "private fixture\n" came back as "private fixture\r\n".
// These tests assert that softserve moves bytes through intact; they are not
// a statement about any platform's line-ending policy, and normalising the
// comparison instead would hide a real corruption behind the same green.
func gitserverRunGit(t *testing.T, directory string, environment []string, args ...string) string {
t.Helper()
args = append([]string{"-c", "core.autocrlf=false"}, args...)
result := command.Command(context.Background(), "git", args...).
WithDir(directory).
WithEnv(environment).
Expand Down Expand Up @@ -242,6 +253,17 @@ func TestSoftservePermissions(t *testing.T) {
service, repository := gitserverTestService(t)
core.AssertTrue(t, service.Health(context.Background()).Value.(Health).Running)

// The confidentiality this pins — a private data dir and an SSH identity
// no one else can read — is a POSIX mode question, and Windows has no
// such bits: os.Stat synthesises 0777 for a directory and 0666 for a
// writable file, so these read 0o777/0o666 there however the real access
// control is set. Windows governs it by ACL, which core.FileMode cannot
// express, let alone assert. Startup above is still exercised on Windows;
// only the unassertable part is skipped.
if runtime.GOOS == "windows" {
t.Skip("POSIX permission bits are not represented on Windows; ACLs govern and FileMode cannot assert them")
}

dataInfo := core.Stat(service.options.DataPath)
core.AssertTrue(t, dataInfo.OK, dataInfo.Error())
core.AssertEqual(t, core.FileMode(0o700), dataInfo.Value.(core.FsFileInfo).Mode().Perm())
Expand Down
18 changes: 15 additions & 3 deletions go/agent/workspace/accept.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"dappco.re/go/inference/agent/gitserver"
"dappco.re/go/inference/agent/queue"
"dappco.re/go/inference/agent/work"
"dappco.re/go/inference/internal/pathx"
commandexec "dappco.re/go/process/exec"
)

Expand Down Expand Up @@ -418,11 +419,22 @@ func (manager *Manager) verifyChangeReview(ctx context.Context, project work.Pro
if !commonResult.OK {
return core.Fail(core.E("workspace.Manager.Apply", "failed to resolve integration repository", commonResult.Err()))
}
clonePath := core.Trim(commonResult.String())
cloneResult := manager.internalAbsolute(clonePath)
if !cloneResult.OK || cloneResult.String() != project.ClonePath || clonePath != project.ClonePath || core.PathBase(clonePath) != "repo.git" {
// Compare the NORMALISED path, not git's raw output. Git prints paths with
// forward slashes on every platform, so on Windows "C:/.../repo.git" never
// equals a filepath-built ClonePath of "C:\...\repo.git" even when both
// name the same directory — and core.PathBase, which matches only the
// platform separator, reads that raw output as having no separator at all
// and hands back the whole path instead of "repo.git". Between them those
// two refused every valid clone on Windows.
//
// The guarantee the raw comparison reached for survives: internalAbsolute
// has already refused anything escaping the internal root, and PathAbs
// cleans away any ".." trickery before the equality test.
cloneResult := manager.internalAbsolute(core.Trim(commonResult.String()))
if !cloneResult.OK || cloneResult.String() != project.ClonePath || pathx.Base(cloneResult.String()) != "repo.git" {
return core.Fail(core.NewError("agent workspace acceptance cached clone is outside the internal root"))
}
clonePath := cloneResult.String()
branchResult := manager.gitOutput(ctx, review.IntegrationPath, nil, "symbolic-ref", "--short", "HEAD")
headResult := manager.gitOutput(ctx, review.IntegrationPath, nil, "rev-parse", "HEAD")
statusResult := manager.gitOutput(ctx, review.IntegrationPath, nil, "status", "--porcelain=v1", "--untracked-files=all")
Expand Down
Loading