Documentation
¶
Overview ¶
Package traceupload builds locally redacted archives of agent sessions.
Index ¶
Constants ¶
const ManifestVersion = "1"
ManifestVersion is the archive schema the CLI emits and the server's ingest worker reads. There is exactly one, and the worker rejects anything else. CLIs and servers of different releases meet, so a new version is an API change that raises apiclient.Protocol.
const MaxUnpackedBytes int64 = 512 << 20
MaxUnpackedBytes bounds an archive's decompressed tar stream: the manifest, every member and the tar headers between them. The ingest worker holds every member in memory and counts every byte it decompresses against this bound, so it is what one upload can cost the shared worker. Bundle.UnpackedSize is the same stream measured as it is written, so the CLI can refuse an archive the worker would reject before uploading it.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bundle ¶
type Bundle struct {
File *os.File
Manifest Manifest
Size int64
// UnpackedSize is the length of the decompressed tar stream, which the
// worker bounds by MaxUnpackedBytes.
UnpackedSize int64
// contains filtered or unexported fields
}
Bundle owns a temporary tar.gz archive. Close removes all temporary data.
func BuildWithProgress ¶
func BuildWithProgress( ctx context.Context, sessions []collector.Session, repository Repository, cliVersion string, progress ProgressFunc, ) (_ *Bundle, err error)
BuildWithProgress redacts sessions, writes a manifest, and calls progress after each session is staged. Calls to progress are serialized.
type Manifest ¶
type Manifest struct {
SchemaVersion string `json:"schema_version"`
CreatedAt time.Time `json:"created_at"`
CLIVersion string `json:"cli_version"`
Repository Repository `json:"repository"`
RepositoryRoots []RepositoryRoots `json:"repository_roots,omitempty"`
Redaction RedactionSummary `json:"redaction"`
Sessions []SessionManifest `json:"sessions"`
}
Manifest is the metadata stored alongside the redacted sessions.
type ProgressFunc ¶
type ProgressFunc func(completed, total int)
ProgressFunc reports how many sessions have been prepared.
type RedactionSummary ¶
type RedactionSummary struct {
Tool string `json:"tool"`
Profile string `json:"profile"`
RuleSet string `json:"rule_set"`
Strategy string `json:"strategy"`
FindingsByType map[string]int `json:"findings_by_type"`
}
RedactionSummary describes the local redaction applied to the archive. Tool, Profile, RuleSet, and Strategy pin exactly which detector produced the counts, so an archive records what it was scanned with rather than leaving it to be inferred from its upload date.
type Repository ¶
type Repository struct {
ID string `json:"id"`
FullName string `json:"full_name"`
RootInventory []RepositoryRoots `json:"-"`
}
Repository identifies the connected repository receiving the sessions.
type RepositoryRoots ¶
type RepositoryRoots struct {
ID string `json:"id"`
FullName string `json:"full_name"`
Roots []string `json:"roots"`
}
RepositoryRoots binds Git-verified roots from this upload invocation to one connected repository.
type SessionFileManifest ¶
type SessionFileManifest struct {
// ID identifies the file within its session.
ID string `json:"id"`
// Name is the file name the source gave it.
Name string `json:"name"`
// Kind is what the file is to its source.
Kind model.FileKind `json:"kind"`
// Member is the tar member holding the redacted bytes.
Member string `json:"member"`
// Root marks the session's own transcript. Exactly one file has it.
Root bool `json:"root,omitempty"`
SizeBytes int64 `json:"size_bytes"`
SHA256 string `json:"sha256"`
FindingsByType map[string]int `json:"findings_by_type"`
}
SessionFileManifest describes one redacted file of a session tree.
The archive stores it under an opaque member the builder chose, not under the path it had on the uploader's machine: reproducing a vendor's directory layout only exists to let a path-based reader run unchanged, and both readers take a file set instead. What survives is what a reader actually needs — the name the source gave the file, which carries its session and agent ids, and what kind of file it is. A source needing a relationship its own files do not record should add a source-owned relation record to the manifest rather than encode it in a directory name.
type SessionManifest ¶
type SessionManifest struct {
Source vendors.Slug `json:"source"`
SessionID string `json:"session_id"`
// RepoRoot and WorktreeRoot are the roots the collector resolved on the
// uploading machine. Optional: an older CLI copy sends neither, and such a
// manifest stays valid at schema_version "1".
RepoRoot string `json:"repo_root,omitempty"`
WorktreeRoot string `json:"worktree_root,omitempty"`
ModifiedAt time.Time `json:"modified_at"`
Files []SessionFileManifest `json:"files"`
SizeBytes int64 `json:"size_bytes"`
FindingsByType map[string]int `json:"findings_by_type"`
}
SessionManifest describes one redacted session tree in the archive. It is the file index: nothing outside it is ingestable, and nothing in it may be absent.
func (SessionManifest) Len ¶
func (m SessionManifest) Len() int
func (SessionManifest) RootFile ¶
func (m SessionManifest) RootFile() (SessionFileManifest, bool)
RootFile returns the session's own transcript.