Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests(integration): add integration tests and test them with a pipeline #34

Merged
merged 13 commits into from
Aug 12, 2024
129 changes: 129 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: tests

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
unit-test:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3
ccoVeille marked this conversation as resolved.
Show resolved Hide resolved

- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'

- name: Install Dependencies
run: |
sudo apt update
sudo apt install -y clang
sudo apt install -y libbpf-dev
sudo apt install -y libseccomp-dev

- name: Build coverage-instrumented binary
run: |
make build-static-libbpfgo
make build-bpf

- name: Run Unit-Test
run: |
mkdir /tmp/unit/
# test packages excluding the ones with libbpfgo
go test \
-cover \
-v \
$(go list ./... | grep -v "github.com/alegrey91/harpoon$" | grep -v ebpf | grep -v cmd) \
-skip TestHarpoon \
-args -test.gocoverdir=/tmp/unit/

- name: Upload cover profiles
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
with:
name: unit-test
path: /tmp/unit/

integration-test:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'
ccoVeille marked this conversation as resolved.
Show resolved Hide resolved

- name: Install Dependencies
run: |
sudo apt update
sudo apt install -y clang
sudo apt install -y libbpf-dev
sudo apt install -y libseccomp-dev

- name: Build coverage-instrumented binary
run: |
make build-static-libbpfgo
make build-bpf
make build-go-cover && sudo make -B install

- name: Run integration test
run: |
mkdir -p /tmp/integration
# we have to run integration tests one-by-one
# otherwhise they will run in parallel.
# since harpoon apply network forwards, these could
# interact with each other and make the test fail.
go test \
-exec sudo \
-cover \
-v main_test.go \
-args -test.gocoverdir=/tmp/integration/

- name: Upload cover profiles
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # ratchet:actions/upload-artifact@v3
with:
name: integration-test
path: /tmp/integration/

code-coverage:

runs-on: ubuntu-latest
needs: [unit-test,integration-test]
steps:
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # ratchet:actions/checkout@v3

- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3
with:
name: unit-test
path: /tmp/unit-test

- uses: actions/download-artifact@v3
with:
name: integration-test
path: /tmp/integration-test

- name: list files
run: |
ls -lah /tmp/unit-test
ls -lah /tmp/integration-test

- name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # ratchet:actions/setup-go@v4
with:
go-version: '1.21'
alegrey91 marked this conversation as resolved.
Show resolved Hide resolved

- name: Calculate total coverage
run: |
go tool \
covdata \
textfmt \
-i=/tmp/unit-test,/tmp/integration-test \
-o code-coverage
go tool \
cover \
-func code-coverage
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ build-go: create-bin-dir
-o ${BINARY_DIR}/${BINARY_NAME} \
.

build-go-cover: create-bin-dir
go mod download
export CURRENT_DIR=$(shell pwd); \
CC=gcc \
CGO_CFLAGS="-I $$CURRENT_DIR/libbpfgo/output" \
alegrey91 marked this conversation as resolved.
Show resolved Hide resolved
CGO_LDFLAGS="-lelf -lz $$CURRENT_DIR/libbpfgo/output/libbpf/libbpf.a" \
go build \
-tags core,ebpf \
-v \
-cover \
-o ${BINARY_DIR}/${BINARY_NAME} \
.

build: create-bin-dir vmlinux.h build-static-libbpfgo build-bpf
go mod download
export CURRENT_DIR=$(shell pwd); \
Expand Down Expand Up @@ -60,6 +73,9 @@ create-bin-dir:
create-output-dir:
mkdir -p ${OUTPUT_DIR}

install:
cp ${BINARY_DIR}/${BINARY_NAME} /usr/local/bin/

clean:
rm -rf ${OUTPUT_DIR}
rm -rf ${BINARY_DIR}
Expand Down
33 changes: 20 additions & 13 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,19 @@ import (
"github.com/spf13/cobra"
alegrey91 marked this conversation as resolved.
Show resolved Hide resolved
)

var excludedPaths []string
var exclude string
var saveAnalysis bool
var (
excludedPaths []string
exclude string
saveAnalysis bool
)

// analyzeCmd represents the create args
var analyzeCmd = &cobra.Command{
Use: "analyze",
Short: "Analyze infers the symbols of functions that are tested by unit-tests",
Long: `
`,
Example: " harpoon analyze --exclude vendor/ /path/to/repo/",
Example: " harpoon analyze --exclude vendor/ -s",
RunE: func(cmd *cobra.Command, args []string) error {
if exclude != "" {
excludedPaths = strings.Split(exclude, ",")
Expand Down Expand Up @@ -85,12 +87,12 @@ var analyzeCmd = &cobra.Command{
pkgPath := getPackagePath(path)
testFile := filepath.Base(path)
testFile = strings.ReplaceAll(testFile, "_test.go", ".test")
_, err = executor.Build(pkgPath, ".harpoon/"+testFile)
_, err = executor.Build(pkgPath, filepath.Join(".harpoon", testFile))
if err != nil {
return fmt.Errorf("failed to build test file: %v", err)
}

symbolsOrig := metadata.NewSymbolsOrigin(".harpoon/" + testFile)
symbolsOrig := metadata.NewSymbolsOrigin(filepath.Join(".harpoon", testFile))

fmt.Println("test: .harpoon/" + testFile)
for _, symbol := range symbolNames {
Expand Down Expand Up @@ -125,13 +127,17 @@ var analyzeCmd = &cobra.Command{
}

// store to file
file, err = os.Create(".harpoon.yml")
if err != nil {
return fmt.Errorf("failed to create symbols list file: %w", err)
if saveAnalysis {
file, err = os.Create("harpoon-report.yml")
if err != nil {
return fmt.Errorf("failed to create symbols list file: %w", err)
}
mw := io.Writer(file)
fmt.Fprintln(mw, symbolsList.String())
alegrey91 marked this conversation as resolved.
Show resolved Hide resolved
fmt.Println("file harpoon-report.yml is ready")
} else {
fmt.Println(symbolsList.String())
}
mw := io.Writer(file)
fmt.Fprintln(mw, symbolsList.String())
fmt.Println("file .harpoon.yml is ready")
return nil
},
}
Expand All @@ -140,7 +146,7 @@ func init() {
rootCmd.AddCommand(analyzeCmd)

analyzeCmd.Flags().StringVarP(&exclude, "exclude", "e", "", "Skip directories specified in the comma separated list")
analyzeCmd.Flags().BoolVarP(&saveAnalysis, "save", "s", false, "Save the result of analysis into a file")
analyzeCmd.Flags().BoolVarP(&saveAnalysis, "save", "S", false, "Save the result of analysis into a file")
}

func shouldSkipPath(path string) bool {
Expand Down Expand Up @@ -171,6 +177,7 @@ func getPackagePath(inputPath string) string {
// Adjust this according to your specific requirements
dirPath = strings.TrimPrefix(dirPath, "../")
dirPath = strings.TrimPrefix(dirPath, "./")
Comment on lines 178 to 179
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange, I would have used something around

https://pkg.go.dev/path/filepath#Clean

and/or

https://pkg.go.dev/path/filepath#Dir

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you try @alegrey91 ?

//dirPath = strings.TrimPrefix(inputPath, rootPath)

// Add "./" at the start again if necessary
dirPath = "./" + dirPath
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filepath.Join

Expand Down
6 changes: 3 additions & 3 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ var buildCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(buildCmd)

buildCmd.Flags().StringVarP(&inputDirectory, "directory", "D", "", "Directory containing harpoon's files")
buildCmd.Flags().StringVarP(&inputDirectory, "directory", "D", "", "Directory containing harpoon's metadata files")
buildCmd.MarkFlagRequired("directory")

buildCmd.Flags().BoolVarP(&saveProfile, "save-profile", "s", false, "Save profile to a file")
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Save profile to a file")
buildCmd.Flags().BoolVarP(&saveProfile, "save", "S", false, "Save profile to a file")
buildCmd.Flags().StringVarP(&profileName, "name", "n", profileName, "Specify a name for the seccomp profile")
}
2 changes: 1 addition & 1 deletion cmd/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"fmt"
"strings"

"github.com/alegrey91/harpoon/internal/captor"
"github.com/alegrey91/harpoon/internal/ebpf/probesfacade/captor"
"github.com/alegrey91/harpoon/internal/writer"
"github.com/spf13/cobra"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cobra should be in a separate block before the packages of the module

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is better open another issue for refactoring all these things

Copy link
Owner Author

@alegrey91 alegrey91 Aug 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be a good PR to fix all the errors reported by golangci-lint that you are going to add

)
Expand Down
6 changes: 3 additions & 3 deletions cmd/hunt.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"io"
"os"

"github.com/alegrey91/harpoon/internal/captor"
"github.com/alegrey91/harpoon/internal/ebpf/probesfacade/captor"
meta "github.com/alegrey91/harpoon/internal/metadata"
"github.com/alegrey91/harpoon/internal/writer"
"github.com/spf13/cobra"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cobra and yaml import should be before the packages of this module

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You didn't change this

Expand All @@ -37,7 +37,7 @@ var huntCmd = &cobra.Command{
Short: "Hunt is like capture but gets a list of functions to be traced",
Long: `
`,
Example: " harpoon hunt --file .harpoon.yaml",
Example: " harpoon hunt --file harpoon-report.yml",
RunE: func(cmd *cobra.Command, args []string) error {
file, err := os.Open(harpoonFile)
if err != nil {
Expand Down Expand Up @@ -91,7 +91,7 @@ var huntCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(huntCmd)

huntCmd.Flags().StringVarP(&harpoonFile, "file", "F", ".harpoon.yaml", "File with the result of analysis")
huntCmd.Flags().StringVarP(&harpoonFile, "file", "F", "harpoon-report.yml", "File with the result of analysis")
huntCmd.MarkFlagRequired("file")

huntCmd.Flags().BoolVarP(&commandOutput, "include-cmd-output", "c", false, "Include the executed command output")
Expand Down
14 changes: 7 additions & 7 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ Harpoon has several commands that you can use.

The common way of using `harpoon` is to execute the available commands as follow:

* [`harpoon analyze`](#analyze-) to analyze the project to infer symbols to be traced. This will create a `.harpoon.yml` file.
* [`harpoon analyze`](#analyze) to infer symbols to be traced from the project root directory. This will create the `harpoon-report.yml` file.

* [`harpoon hunt`](#hunt-) by passing the `.harpoon.yml` file to trace the functions and get their system calls. This will generate the `./harpoon/` directory with the metadata that contain the system calls traced.
* [`harpoon hunt`](#hunt) by passing the `harpoon-report.yml` file to trace the functions and get their system calls. This will generate the `./harpoon/` directory with the metadata that contain the system calls traced.

* [`harpoon build`](#build-️) to read the metadata files and provide the **seccomp** profile.
* [`harpoon build`](#build) to read the metadata files and provide the **seccomp** profile.

## Analyze

The `analyze` command is used to analyze the project's folder and get the list of function symbols you want to trace.

Additionally it automatically build the test binary and place them into the `harpoon/` directory.

The result of this command is the `.harpoon.yml` file with the list of test binaries followed by their function symbols that are currently tested.
The result of this command is the `harpoon-report.yml` file with the list of test binaries followed by their function symbols that are currently tested.

Run it on your project folder:

```sh
sudo harpoon analyze --exclude .git/ .
sudo harpoon analyze --exclude .git/
```

## Build
Expand Down Expand Up @@ -51,7 +51,7 @@ The command needs a file as input paramenter that is the result of the `analyze`
This will loop over the entries of the file, capturing the system calls of each entry.

```sh
harpoon hunt --file .harpoon.yml -S
harpoon hunt --file harpoon-report.yml -S
```

This will create the directory `harpoon/` with the list of system calls traced from the execution of the different test binaries present in the `.harpoon.yml` file.
This will create the directory `harpoon/` with the list of system calls traced from the execution of the different test binaries present in the `harpoon-report.yml` file.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ require (
require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/tools v0.1.12 // indirect
)

require (
github.com/rogpeppe/go-internal v1.12.0
github.com/spf13/cobra v1.8.0
golang.org/x/sys v0.16.0 // indirect
gopkg.in/yaml.v2 v2.4.0
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
github.com/seccomp/libseccomp-golang v0.10.0/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
Expand All @@ -22,6 +24,8 @@ golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import (
"sync"
"unsafe"

probes "github.com/alegrey91/harpoon/internal/ebpf/probesfacade"
embedded "github.com/alegrey91/harpoon/internal/embeddable"
"github.com/alegrey91/harpoon/internal/executor"
probes "github.com/alegrey91/harpoon/internal/probesfacade"
bpf "github.com/aquasecurity/libbpfgo"
alegrey91 marked this conversation as resolved.
Show resolved Hide resolved
)

Expand Down
Loading
Loading