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
58 changes: 2 additions & 56 deletions cmd/run.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package cmd

import (
"archive/tar"
"io"
"os"
"path/filepath"

"github.com/Snider/Borg/pkg/matrix"
"github.com/spf13/cobra"
)

Expand All @@ -17,57 +13,7 @@ func NewRunCmd() *cobra.Command {
Short: "Run a Terminal Isolation Matrix.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
matrixFile := args[0]

// Create a temporary directory to unpack the matrix file.
tempDir, err := os.MkdirTemp("", "borg-run-*")
if err != nil {
return err
}
defer os.RemoveAll(tempDir)

// Unpack the matrix file.
file, err := os.Open(matrixFile)
if err != nil {
return err
}
defer file.Close()

tr := tar.NewReader(file)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}

path := filepath.Join(tempDir, header.Name)
if header.Typeflag == tar.TypeDir {
if err := os.MkdirAll(path, 0755); err != nil {
return err
}
continue
}

outFile, err := os.Create(path)
if err != nil {
return err
}
defer outFile.Close()
if _, err := io.Copy(outFile, tr); err != nil {
return err
}
}

// Run the matrix.
runc := execCommand("runc", "run", "borg-container")
runc.Dir = tempDir
runc.Stdout = os.Stdout
runc.Stderr = os.Stderr
runc.Stdin = os.Stdin
return runc.Run()
return matrix.Run(args[0])
},
}
}
Expand Down
33 changes: 12 additions & 21 deletions cmd/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,21 @@ import (
"github.com/Snider/Borg/pkg/matrix"
)

func helperProcess(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}

func TestHelperProcess(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
os.Exit(0)
}

func TestRunCmd_Good(t *testing.T) {
// Create a dummy matrix file.
matrixPath := createDummyMatrix(t)

// Mock the exec.Command function.
origExecCommand := execCommand
execCommand = helperProcess
// Mock the exec.Command function in the matrix package.
origExecCommand := matrix.ExecCommand
matrix.ExecCommand = func(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
t.Cleanup(func() {
execCommand = origExecCommand
matrix.ExecCommand = origExecCommand
})

// Run the run command.
Expand Down Expand Up @@ -90,8 +81,8 @@ func createDummyMatrix(t *testing.T) string {

tw := tar.NewWriter(matrixFile)

// Add a dummy config.json.
configContent := []byte(matrix.DefaultConfigJSON)
// Add a dummy config.json. This is not a valid config, but it's enough to test the run command.
configContent := []byte(`{}`)
hdr := &tar.Header{
Name: "config.json",
Mode: 0600,
Expand Down
149 changes: 133 additions & 16 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,44 @@ borg collect website [url] [flags]
./borg collect website https://google.com --output website.dat --depth 1
```

#### `collect github repos`

Collects all public repositories for a user or organization.

**Usage:**
```
borg collect github repos [user-or-org] [flags]
```

**Example:**
```
./borg collect github repos Snider
```

#### `collect github release`

Downloads the latest release of a file from GitHub releases.

**Usage:**
```
borg collect github release [repository-url] [flags]
```

**Flags:**
- `--output string`: Output directory for the downloaded file (default ".")
- `--pack`: Pack all assets into a DataNode
- `--file string`: The file to download from the release
- `--version string`: The version to check against

**Example:**
```
# Download the latest release of the 'borg' executable
./borg collect github release https://github.com/Snider/Borg --file borg

# Pack all assets from the latest release into a DataNode
./borg collect github release https://github.com/Snider/Borg --pack --output borg-release.dat
```

#### `collect pwa`

Collects a single PWA and stores it in a DataNode.
Expand All @@ -67,6 +105,24 @@ borg collect pwa [flags]
./borg collect pwa --uri https://squoosh.app --output squoosh.dat
```

### `compile`

Compiles a `Borgfile` into a Terminal Isolation Matrix.

**Usage:**
```
borg compile [flags]
```

**Flags:**
- `--file string`: Path to the Borgfile (default "Borgfile")
- `--output string`: Path to the output matrix file (default "a.matrix")

**Example:**
```
./borg compile -f my-borgfile -o my-app.matrix
```

### `serve`

Serves the contents of a packaged DataNode or Terminal Isolation Matrix file using a static file server.
Expand Down Expand Up @@ -116,33 +172,94 @@ To create a Matrix, use the `--format matrix` flag with any of the `collect` sub
./borg collect github repo https://github.com/Snider/Borg --output borg.matrix --format matrix
```

You can then execute the Matrix with `runc`:
The `borg run` command is used to execute a Terminal Isolation Matrix. This command handles the unpacking and execution of the matrix in a secure, isolated environment using `runc`. This ensures that the payload can be safely analyzed without affecting the host system.

**Example:**
```
# Create a directory for the bundle
mkdir borg-bundle
./borg run borg.matrix
```

## Programmatic Usage

The `examples` directory contains a number of Go programs that demonstrate how to use the `borg` package programmatically.

# Unpack the matrix into the bundle directory
tar -xf borg.matrix -C borg-bundle
### Inspecting a DataNode

# Run the bundle
cd borg-bundle
runc run borg
The `inspect_datanode` example demonstrates how to read, decompress, and walk a `.dat` file.

**Usage:**
```
go run examples/inspect_datanode/main.go <path to .dat file>
```

## Inspecting a DataNode
### Creating a Matrix Programmatically

The `examples` directory contains a Go program that can be used to inspect the contents of a `.dat` file.
The `create_matrix_programmatically` example demonstrates how to create a Terminal Isolation Matrix from scratch.

**Usage:**
```
go run examples/inspect_datanode.go <path to .dat file>
go run examples/create_matrix_programmatically/main.go
```

**Example:**
### Running a Matrix Programmatically

The `run_matrix_programmatically` example demonstrates how to run a Terminal Isolation Matrix using the `borg` package.

**Usage:**
```
# First, create a .dat file
./borg collect github repo https://github.com/Snider/Borg --output borg.dat
go run examples/run_matrix_programmatically/main.go
```

### Collecting a Website

The `collect_website` example demonstrates how to collect a website and package it into a `.dat` file.

**Usage:**
```
go run examples/collect_website/main.go
```

### Collecting a GitHub Release

The `collect_github_release` example demonstrates how to collect the latest release of a GitHub repository.

**Usage:**
```
go run examples/collect_github_release/main.go
```

### Collecting All Repositories for a User

The `all` example demonstrates how to collect all public repositories for a GitHub user.

# Then, inspect it
go run examples/inspect_datanode.go borg.dat
**Usage:**
```
go run examples/all/main.go
```

### Collecting a PWA

The `collect_pwa` example demonstrates how to collect a Progressive Web App and package it into a `.dat` file.

**Usage:**
```
go run examples/collect_pwa/main.go
```

### Collecting a GitHub Repository

The `collect_github_repo` example demonstrates how to clone a GitHub repository and package it into a `.dat` file.

**Usage:**
```
go run examples/collect_github_repo/main.go
```

### Serving a DataNode

The `serve` example demonstrates how to serve the contents of a `.dat` file over HTTP.

**Usage:**
```
go run examples/serve/main.go
```
41 changes: 39 additions & 2 deletions examples/all/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
package main

import "fmt"
import (
"context"
"fmt"
"log"
"os"

"github.com/Snider/Borg/pkg/github"
"github.com/Snider/Borg/pkg/vcs"
)

func main() {
fmt.Println("This is a placeholder for the 'all' example.")
log.Println("Collecting all repositories for a user...")

repos, err := github.NewGithubClient().GetPublicRepos(context.Background(), "Snider")
if err != nil {
log.Fatalf("Failed to get public repos: %v", err)
}

cloner := vcs.NewGitCloner()

for _, repo := range repos {
log.Printf("Cloning %s...", repo)
dn, err := cloner.CloneGitRepository(fmt.Sprintf("https://github.com/%s", repo), nil)
if err != nil {
log.Printf("Failed to clone %s: %v", repo, err)
continue
}

tarball, err := dn.ToTar()
if err != nil {
log.Printf("Failed to serialize %s to tar: %v", repo, err)
continue
}

err = os.WriteFile(fmt.Sprintf("%s.dat", repo), tarball, 0644)
if err != nil {
log.Printf("Failed to write %s.dat: %v", repo, err)
continue
}
log.Printf("Successfully created %s.dat", repo)
}
}
39 changes: 37 additions & 2 deletions examples/collect_github_release/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
package main

import "fmt"
import (
"log"
"os"

"github.com/Snider/Borg/pkg/github"
)

func main() {
fmt.Println("This is a placeholder for the 'collect github release' example.")
log.Println("Collecting GitHub release...")

owner, repo, err := github.ParseRepoFromURL("https://github.com/Snider/Borg")
if err != nil {
log.Fatalf("Failed to parse repo from URL: %v", err)
}

release, err := github.GetLatestRelease(owner, repo)
if err != nil {
log.Fatalf("Failed to get latest release: %v", err)
}

if len(release.Assets) == 0 {
log.Println("No assets found in the latest release.")
return
}

asset := release.Assets[0]
log.Printf("Downloading asset: %s", asset.GetName())

data, err := github.DownloadReleaseAsset(asset)
if err != nil {
log.Fatalf("Failed to download asset: %v", err)
}

err = os.WriteFile(asset.GetName(), data, 0644)
if err != nil {
log.Fatalf("Failed to write asset to file: %v", err)
}

log.Printf("Successfully downloaded asset to %s", asset.GetName())
}
Loading