feat: Implement Go examples and refactor matrix execution
- Implements all placeholder Go examples in the `examples` directory. - Corrects the `run_matrix_programmatically` example to use the `borg` package. - Refactors the code to centralize the matrix execution logic in the `matrix` package. - Updates the documentation to include a new "Programmatic Usage" section that describes all of the Go examples. - Updates the "Terminal Isolation Matrix" section to remove manual 'runc' instructions, emphasizing that 'borg run' handles this process to maintain security and isolation. - Adds missing examples for 'collect github repos', 'collect github release', and 'compile' commands to the documentation.
This commit is contained in:
parent
952a287872
commit
80aacc85a4
10 changed files with 409 additions and 156 deletions
58
cmd/run.go
58
cmd/run.go
|
|
@ -1,11 +1,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Snider/Borg/pkg/matrix"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -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])
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
169
docs/index.md
169
docs/index.md
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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`:
|
||||
```
|
||||
# Create a directory for the bundle
|
||||
mkdir borg-bundle
|
||||
|
||||
# Unpack the matrix into the bundle directory
|
||||
tar -xf borg.matrix -C borg-bundle
|
||||
|
||||
# Run the bundle
|
||||
cd borg-bundle
|
||||
runc run borg
|
||||
```
|
||||
|
||||
## Inspecting a DataNode
|
||||
|
||||
The `examples` directory contains a Go program that can be used to inspect the contents of a `.dat` file.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
go run examples/inspect_datanode.go <path to .dat file>
|
||||
```
|
||||
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:**
|
||||
```
|
||||
# First, create a .dat file
|
||||
./borg collect github repo https://github.com/Snider/Borg --output borg.dat
|
||||
|
||||
# Then, inspect it
|
||||
go run examples/inspect_datanode.go borg.dat
|
||||
./borg run borg.matrix
|
||||
```
|
||||
|
||||
## Programmatic Usage
|
||||
|
||||
The `examples` directory contains a number of Go programs that demonstrate how to use the `borg` package programmatically.
|
||||
|
||||
### Inspecting a DataNode
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
### Creating a Matrix Programmatically
|
||||
|
||||
The `create_matrix_programmatically` example demonstrates how to create a Terminal Isolation Matrix from scratch.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
go run examples/create_matrix_programmatically/main.go
|
||||
```
|
||||
|
||||
### Running a Matrix Programmatically
|
||||
|
||||
The `run_matrix_programmatically` example demonstrates how to run a Terminal Isolation Matrix using the `borg` package.
|
||||
|
||||
**Usage:**
|
||||
```
|
||||
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.
|
||||
|
||||
**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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,30 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Snider/Borg/pkg/vcs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("This is a placeholder for the 'collect github repo' example.")
|
||||
log.Println("Collecting GitHub repo...")
|
||||
|
||||
cloner := vcs.NewGitCloner()
|
||||
dn, err := cloner.CloneGitRepository("https://github.com/Snider/Borg", nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to clone repository: %v", err)
|
||||
}
|
||||
|
||||
tarball, err := dn.ToTar()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to serialize datanode to tar: %v", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile("repo.dat", tarball, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write datanode file: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully created repo.dat")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,37 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Snider/Borg/pkg/pwa"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("This is a placeholder for the 'collect pwa' example.")
|
||||
log.Println("Collecting PWA...")
|
||||
|
||||
client := pwa.NewPWAClient()
|
||||
pwaURL := "https://squoosh.app"
|
||||
|
||||
manifestURL, err := client.FindManifest(pwaURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to find manifest: %v", err)
|
||||
}
|
||||
|
||||
dn, err := client.DownloadAndPackagePWA(pwaURL, manifestURL, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to download and package PWA: %v", err)
|
||||
}
|
||||
|
||||
tarball, err := dn.ToTar()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to serialize datanode to tar: %v", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile("pwa.dat", tarball, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write datanode file: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully created pwa.dat")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,32 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Snider/Borg/pkg/website"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("This is a placeholder for the 'collect website' example.")
|
||||
log.Println("Collecting website...")
|
||||
|
||||
// Download and package the website.
|
||||
dn, err := website.DownloadAndPackageWebsite("https://example.com", 2, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to collect website: %v", err)
|
||||
}
|
||||
|
||||
// Serialize the DataNode to a tarball.
|
||||
tarball, err := dn.ToTar()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to serialize datanode to tar: %v", err)
|
||||
}
|
||||
|
||||
// Write the tarball to a file.
|
||||
err = os.WriteFile("website.dat", tarball, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to write datanode file: %v", err)
|
||||
}
|
||||
|
||||
log.Println("Successfully created website.dat")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,73 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/Snider/Borg/pkg/matrix"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Open the matrix file.
|
||||
matrixFile, err := os.Open("programmatic.matrix")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to open matrix file (run create_matrix_programmatically first): %v", err)
|
||||
}
|
||||
defer matrixFile.Close()
|
||||
log.Println("Executing matrix with Borg...")
|
||||
|
||||
// Create a temporary directory to unpack the matrix.
|
||||
tempDir, err := os.MkdirTemp("", "borg-run-example-*")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create temporary directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
log.Printf("Unpacking matrix to %s", tempDir)
|
||||
|
||||
// Unpack the tar archive.
|
||||
tr := tar.NewReader(matrixFile)
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break // End of archive
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read tar header: %v", err)
|
||||
}
|
||||
|
||||
target := filepath.Join(tempDir, header.Name)
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
log.Fatalf("Failed to create directory: %v", err)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
outFile, err := os.Create(target)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create file: %v", err)
|
||||
}
|
||||
if _, err := io.Copy(outFile, tr); err != nil {
|
||||
log.Fatalf("Failed to write file content: %v", err)
|
||||
}
|
||||
outFile.Close()
|
||||
default:
|
||||
log.Printf("Skipping unsupported type: %c in %s", header.Typeflag, header.Name)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Executing matrix with runc...")
|
||||
|
||||
// Execute the matrix using runc.
|
||||
cmd := exec.Command("runc", "run", "borg-container-example")
|
||||
cmd.Dir = tempDir
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
// Execute the matrix using the Borg package.
|
||||
if err := matrix.Run("programmatic.matrix"); err != nil {
|
||||
log.Fatalf("Failed to run matrix: %v", err)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,42 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/Snider/Borg/pkg/compress"
|
||||
"github.com/Snider/Borg/pkg/tarfs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("This is a placeholder for the 'serve' example.")
|
||||
log.Println("Serving datanode...")
|
||||
|
||||
// Create a dummy datanode for serving.
|
||||
err := os.WriteFile("serve.dat", []byte{}, 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create dummy datanode: %v", err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile("serve.dat")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to read datanode: %v", err)
|
||||
}
|
||||
|
||||
decompressed, err := compress.Decompress(data)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to decompress datanode: %v", err)
|
||||
}
|
||||
|
||||
fs, err := tarfs.New(decompressed)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create tarfs: %v", err)
|
||||
}
|
||||
|
||||
http.Handle("/", http.FileServer(fs))
|
||||
log.Println("Listening on :8080...")
|
||||
err = http.ListenAndServe(":8080", nil)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start server: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
62
pkg/matrix/run.go
Normal file
62
pkg/matrix/run.go
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package matrix
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// Run executes a Terminal Isolation Matrix from a given path.
|
||||
func Run(matrixPath string) error {
|
||||
// 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(matrixPath)
|
||||
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 := exec.Command("runc", "run", "borg-container")
|
||||
runc.Dir = tempDir
|
||||
runc.Stdout = os.Stdout
|
||||
runc.Stderr = os.Stderr
|
||||
runc.Stdin = os.Stdin
|
||||
return runc.Run()
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue