mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: collect workspace logs in support bundles (#26694)
Add workspace-side file collection to `coder support bundle` via repeatable --workspace-file flags. The agent resolves the requested paths or globs inside the remote workspace and streams back a tar with a manifest and the collected files; nothing is read from the machine running the command. - Add POST /api/v0/bundle-files to the agent's agentfiles package. - Expand env vars in the agent's environment; paths must then be absolute or start with ~/ (the agent user's home directory). - Support ** globs and tail oversized files. - Record requested patterns, per-path errors, truncation, and the applied limits in a manifest. - Unpack the archive into the bundle under agent/workspace_files/, recording dropped entries in collection_errors.txt. - Write a manifest-only archive marking collection as unsupported for agents that predate the endpoint. - Bound collection: 64 KB request body, 10000 files, 10 MiB per file, 100 MiB total including archive overhead, 110 MiB client-side read cap, 5 minute timeout. Closes #26020
This commit is contained in:
@@ -2,7 +2,10 @@ package testutil
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
@@ -59,3 +62,39 @@ func CreateZip(t testing.TB, files map[string]string) []byte {
|
||||
require.NoError(t, err)
|
||||
return za
|
||||
}
|
||||
|
||||
// Reads every entry of the in-memory tar into a map keyed by entry name.
|
||||
func ReadTar(t testing.TB, data []byte) map[string][]byte {
|
||||
t.Helper()
|
||||
|
||||
entries := make(map[string][]byte)
|
||||
tr := tar.NewReader(bytes.NewReader(data))
|
||||
for {
|
||||
hdr, err := tr.Next()
|
||||
if errors.Is(err, io.EOF) {
|
||||
return entries
|
||||
}
|
||||
require.NoError(t, err)
|
||||
content, err := io.ReadAll(tr)
|
||||
require.NoError(t, err)
|
||||
entries[hdr.Name] = content
|
||||
}
|
||||
}
|
||||
|
||||
// Reads every entry of the in-memory zip into a map keyed by entry name.
|
||||
func ReadZip(t testing.TB, data []byte) map[string][]byte {
|
||||
t.Helper()
|
||||
|
||||
zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
require.NoError(t, err)
|
||||
entries := make(map[string][]byte, len(zr.File))
|
||||
for _, file := range zr.File {
|
||||
rc, err := file.Open()
|
||||
require.NoError(t, err)
|
||||
content, err := io.ReadAll(rc)
|
||||
_ = rc.Close()
|
||||
require.NoError(t, err)
|
||||
entries[file.Name] = content
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user