Keep run logs opaque and streamline transfers
This commit is contained in:
@@ -1,14 +1,10 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -181,13 +177,22 @@ func TestDistributionBuildIsolationUsesPluginJobWorkspaceAndDistinctPackageState
|
||||
worker := &Worker{cfg: workerTestConfig(t), client: client}
|
||||
worker.state.RunEndpointID = "run-test"
|
||||
worker.state.SessionToken = "session-token"
|
||||
artifactDir := t.TempDir()
|
||||
firstArtifactPath := filepath.Join(artifactDir, "alpha.bin")
|
||||
secondArtifactPath := filepath.Join(artifactDir, "beta.bin")
|
||||
if err := os.WriteFile(firstArtifactPath, []byte("alpha archive"), 0o600); err != nil {
|
||||
t.Fatalf("write first artifact: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(secondArtifactPath, []byte("beta archive"), 0o600); err != nil {
|
||||
t.Fatalf("write second artifact: %v", err)
|
||||
}
|
||||
client.buildInput = firstInput
|
||||
if err := worker.uploadDistributionArtifact(context.Background(), firstAssignment, firstInput.ArtifactID, []byte("alpha archive")); err != nil {
|
||||
if err := worker.uploadDistributionArtifact(context.Background(), firstAssignment, firstInput.ArtifactID, firstArtifactPath); err != nil {
|
||||
t.Fatalf("upload first artifact: %v", err)
|
||||
}
|
||||
client.artifactPayload = nil
|
||||
client.buildInput = secondInput
|
||||
if err := worker.uploadDistributionArtifact(context.Background(), secondAssignment, secondInput.ArtifactID, []byte("beta archive")); err != nil {
|
||||
if err := worker.uploadDistributionArtifact(context.Background(), secondAssignment, secondInput.ArtifactID, secondArtifactPath); err != nil {
|
||||
t.Fatalf("upload second artifact: %v", err)
|
||||
}
|
||||
if len(client.artifactOpenRequests) != 2 {
|
||||
@@ -201,38 +206,6 @@ func TestDistributionBuildIsolationUsesPluginJobWorkspaceAndDistinctPackageState
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateDistributionArchiveIncludesExecutableAndConfigForSupportedFormats(t *testing.T) {
|
||||
for _, format := range []string{"tar.gz", "zip"} {
|
||||
t.Run(format, func(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
executableName := "run"
|
||||
if format == "zip" {
|
||||
executableName = "run.exe"
|
||||
}
|
||||
binaryPath := filepath.Join(root, executableName)
|
||||
configPath := filepath.Join(root, "config.json")
|
||||
if err := os.WriteFile(binaryPath, []byte("binary"), 0o700); err != nil {
|
||||
t.Fatalf("write binary: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(configPath, []byte(`{"kind":"run"}`), 0o600); err != nil {
|
||||
t.Fatalf("write config: %v", err)
|
||||
}
|
||||
archivePath := filepath.Join(root, "package."+strings.ReplaceAll(format, ".", ""))
|
||||
if err := createDistributionArchive(archivePath, format, binaryPath, configPath); err != nil {
|
||||
t.Fatalf("create archive: %v", err)
|
||||
}
|
||||
payload, err := os.ReadFile(archivePath)
|
||||
if err != nil {
|
||||
t.Fatalf("read archive: %v", err)
|
||||
}
|
||||
entries := archiveEntries(t, format, payload)
|
||||
if !entries[executableName] || !entries["config.json"] {
|
||||
t.Fatalf("expected executable and config in %s archive, got %+v", format, entries)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareDistributionSourceCopiesTrustedRunSourceIntoWorkspace(t *testing.T) {
|
||||
sourceRoot := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(sourceRoot, "go.mod"), []byte("module example.test/trusted\n\ngo 1.24\n"), 0o600); err != nil {
|
||||
@@ -269,23 +242,14 @@ func TestPrepareDistributionSourceCopiesTrustedRunSourceIntoWorkspace(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateDistributionBuildInputRejectsUnapprovedClientSource(t *testing.T) {
|
||||
func TestValidateDistributionBuildInputRejectsLegacyClientManagerBuilds(t *testing.T) {
|
||||
assignment := protocol.RunJobAssignment{JobID: "job-build", ServerInstanceID: "server-build", RunEndpointID: "run-build"}
|
||||
base := protocol.DistributionBuildInputResponse{
|
||||
input := protocol.DistributionBuildInputResponse{
|
||||
JobID: assignment.JobID, ComponentKind: "client-manager", ServerInstanceID: assignment.ServerInstanceID, RunEndpointID: assignment.RunEndpointID,
|
||||
PluginID: "game.scum", TargetOS: "linux", TargetArch: "amd64", PackageFormat: "tar.gz", ArtifactID: "artifact-build", OutputFilename: "manager", AuthKey: "key", SourceRevision: "main",
|
||||
}
|
||||
for _, repository := range []string{"http://example.test/manager.git", "https://token@example.test/manager.git", "https://example.test/manager.git?ref=main"} {
|
||||
input := base
|
||||
input.RepositoryURL = repository
|
||||
if err := validateDistributionBuildInput(assignment, input); err == nil {
|
||||
t.Fatalf("expected repository %q to be rejected", repository)
|
||||
}
|
||||
}
|
||||
base.RepositoryURL = "https://example.test/manager.git"
|
||||
base.SourceRevision = ""
|
||||
if err := validateDistributionBuildInput(assignment, base); err == nil {
|
||||
t.Fatal("expected an unpinned client-manager source to be rejected")
|
||||
if err := validateDistributionBuildInput(assignment, input); err == nil || !strings.Contains(err.Error(), "component kind") {
|
||||
t.Fatalf("expected legacy component kind to be rejected, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,99 +265,7 @@ func TestValidateDistributionBuildInputAllowsDedicatedRunIdentity(t *testing.T)
|
||||
}
|
||||
input.WorkspaceSeed = ""
|
||||
input.ComponentKind = "client-manager"
|
||||
input.PackageFormat = "zip"
|
||||
input.RepositoryURL = "https://example.test/manager.git"
|
||||
input.SourceRevision = "main"
|
||||
if err := validateDistributionBuildInput(assignment, input); err == nil {
|
||||
t.Fatal("client-manager build must remain bound to its assigned builder")
|
||||
if err := validateDistributionBuildInput(assignment, input); err == nil || !strings.Contains(err.Error(), "component kind") {
|
||||
t.Fatalf("expected client-manager build to be rejected, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func archiveEntries(t *testing.T, format string, payload []byte) map[string]bool {
|
||||
t.Helper()
|
||||
entries := map[string]bool{}
|
||||
if format == "zip" {
|
||||
reader, err := zip.NewReader(bytes.NewReader(payload), int64(len(payload)))
|
||||
if err != nil {
|
||||
t.Fatalf("open zip: %v", err)
|
||||
}
|
||||
for _, file := range reader.File {
|
||||
entries[file.Name] = true
|
||||
}
|
||||
return entries
|
||||
}
|
||||
gzipReader, err := gzip.NewReader(bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
t.Fatalf("open gzip: %v", err)
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
reader := tar.NewReader(gzipReader)
|
||||
for {
|
||||
header, err := reader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("read tar: %v", err)
|
||||
}
|
||||
entries[header.Name] = true
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func extractArchive(t *testing.T, format string, payload []byte, destination string) {
|
||||
t.Helper()
|
||||
if format == "zip" {
|
||||
reader, err := zip.NewReader(bytes.NewReader(payload), int64(len(payload)))
|
||||
if err != nil {
|
||||
t.Fatalf("open zip: %v", err)
|
||||
}
|
||||
for _, file := range reader.File {
|
||||
input, err := file.Open()
|
||||
if err != nil {
|
||||
t.Fatalf("open zip entry: %v", err)
|
||||
}
|
||||
body, err := io.ReadAll(input)
|
||||
closeErr := input.Close()
|
||||
if err != nil || closeErr != nil {
|
||||
t.Fatalf("read zip entry: err=%v close=%v", err, closeErr)
|
||||
}
|
||||
mode := os.FileMode(0o600)
|
||||
if file.Name == "run" || strings.HasSuffix(file.Name, ".exe") {
|
||||
mode = 0o700
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(destination, file.Name), body, mode); err != nil {
|
||||
t.Fatalf("write zip entry: %v", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
gzipReader, err := gzip.NewReader(bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
t.Fatalf("open gzip: %v", err)
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
reader := tar.NewReader(gzipReader)
|
||||
for {
|
||||
header, err := reader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("read tar: %v", err)
|
||||
}
|
||||
mode := os.FileMode(header.Mode)
|
||||
if err := os.WriteFile(filepath.Join(destination, header.Name), mustReadAll(t, reader), mode); err != nil {
|
||||
t.Fatalf("write tar entry: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mustReadAll(t *testing.T, reader io.Reader) []byte {
|
||||
t.Helper()
|
||||
body, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
t.Fatalf("read archive entry: %v", err)
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user