Compare commits

...

4 Commits

8 changed files with 174 additions and 50 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"path"
) )
const ( const (
@ -17,13 +18,13 @@ var (
) )
type Config struct { type Config struct {
// ProjectPath is where all git repositories will be downloaded to // ProjectPath is the location on your host where all dev relevant folders will be stored to
ProjectPath string ProjectPath string
// VolumePath is where all the persisitant data will be saved to // VolumePath is where all the persisitant data will be stored
VolumePath string VolumePath string
// // Credentials for UI login
LoginCredential LoginCredential LoginCredential LoginCredential
// // key is repository name, for example, "repository-ee"
RepositoryConfig map[string]RepositoryConfig RepositoryConfig map[string]RepositoryConfig
} }
@ -72,13 +73,16 @@ func (config *Config) Summarize() {
} }
} }
// initializeConfig will set up the mandatory dev information for the first time.
// such as devtool path, login credential
// The configuration also can be updated later
func initializeConfig(w io.WriteCloser) (*Config, error) { func initializeConfig(w io.WriteCloser) (*Config, error) {
config := &Config{} config := &Config{}
fmt.Printf("Set the project path: ") fmt.Printf("Initialize devtool path:\n (Project path will store volumes and repositories)")
fmt.Scanf("%s", &(config.ProjectPath)) fmt.Scanf("%s", &(config.ProjectPath))
fmt.Printf("Set the volume path: ") // generate volume path automatically
fmt.Scanf("%s", &(config.VolumePath)) config.VolumePath = path.Join(config.ProjectPath, "volumes")
var loginCredential LoginCredential var loginCredential LoginCredential
fmt.Printf("Set login credential username(admin): ") fmt.Printf("Set login credential username(admin): ")

View File

@ -4,12 +4,9 @@ import (
"log" "log"
"ocl/portainer-devtool/configs" "ocl/portainer-devtool/configs"
"ocl/portainer-devtool/tasks" "ocl/portainer-devtool/tasks"
"ocl/portainer-devtool/utils"
"strconv"
) )
func main() { func main() {
config, err := configs.GetConfig() config, err := configs.GetConfig()
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
@ -18,42 +15,14 @@ func main() {
config.Summarize() config.Summarize()
// Init tasks // Init tasks
taskItems := []tasks.Tasker{ taskItems := []tasks.Tasker{
tasks.NewGenerateJwtTokenTask(config), tasks.NewGenerateJwtTokenTask(config),
tasks.NewCurlLookupTask(),
tasks.NewCodeSecurityScanTask(),
tasks.NewListDevToolCommandTask(config),
tasks.NewExitTask(),
} }
for { tasks.ListCommandMenu(taskItems, "Which repository of action do you want operate:")
printMainMenu := func() {
utils.PrintMenu("Which repository of action do you want operate:", taskItems)
// utils.MenuPrint("Which repository or action do you want to operate:", `
// 1. Portainer EE Repository
// 2. Portainer CE Repository
// 3. Portainer Agent Repository
// 4. Others
// 5. Quit`)
}
option := utils.SelectMenuItem(printMainMenu)
index, err := strconv.Atoi(option)
if err != nil {
log.Printf("please type the option number\n")
continue
}
if index < 1 || index > len(taskItems) {
log.Printf("no such option %s, please select again\n", option)
continue
}
err = taskItems[index-1].Execute()
if err != nil {
log.Fatalln(err)
}
}
} }

View File

@ -0,0 +1,35 @@
package tasks
import (
"ocl/portainer-devtool/utils"
)
type CodeSecurityScanTask struct {
}
func NewCodeSecurityScanTask() *CodeSecurityScanTask {
return &CodeSecurityScanTask{}
}
func (task *CodeSecurityScanTask) Execute() error {
utils.SuccessPrint(`
1. Scan client with snyk: "snyk test"
2. Scan server with snyk: "cd api && snyk test"
3. If snyk is not authenticated: "snyk auth"
4. Specify the severity threshold: "snyk test --severity-threshold=<low|medium|high|critical>"
5. Other commands with snyk: "snyk --help"
`)
utils.SuccessPrint(`
Steps to scan portainer image with Trivy:
1. Build the local image: "docker build -t oscarzhou/portainer:dev-ee -f build/linux/Dockfile ."
2. Scan with trivy: 'docker run --rm -v "/var/run/docker.sock":"/var/run/docker.sock" aquasec/trivy:latest image oscarzhou/portainer:dev-ee'
3. Other commands with trivy: 'docker run --rm -v "/var/run/docker.sock":"/var/run/docker.sock" aquasec/trivy:latest --help'
`)
return nil
}
func (task *CodeSecurityScanTask) String() string {
return "Code Security Scan"
}

48
go/tasks/curl_lookup.go Normal file
View File

@ -0,0 +1,48 @@
package tasks
import (
"fmt"
"ocl/portainer-devtool/utils"
)
type CurlLookupTask struct {
}
func NewCurlLookupTask() *CurlLookupTask {
return &CurlLookupTask{}
}
func (task *CurlLookupTask) Execute() error {
var option string
utils.InputPrint("1.POST 2.GET 3.PUT 4.DELETE: ")
fmt.Scanf("%s", &option)
switch option {
case "1", "POST", "post":
utils.HighlightPrint("POST Command:")
utils.SuccessPrint("curl -d '{\"repository\":\"https://github.com/portainer/portainer-ee\",\"username\":\"oscarzhou\", \"password\":\"your PAT\"}' -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOjEsInNjb3BlIjoiZGVmYXVsdCIsImZvcmNlQ2hhbmdlUGFzc3dvcmQiOmZhbHNlLCJleHAiOjE2NjAwMzQ2MjUsImlhdCI6MTY2MDAwNTgyNX0.S0UbPO4POD9kbuWOmvO9WR6LY6v424bpGw46rlEkNs0' http://127.0.0.1:9000/api/gitops/repo/refs")
break
case "2", "GET", "get":
utils.HighlightPrint("GET Command:")
utils.SuccessPrint("curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOjEsInNjb3BlIjoiZGVmYXVsdCIsImZvcmNlQ2hhbmdlUGFzc3dvcmQiOmZhbHNlLCJleHAiOjE2NTUxMTg2ODUsImlhdCI6MTY1NTA4OTg4NX0.mJSZomeiEpRlz36MxSsLFWpUbA0BHRXWYijsZAo1NWc' http://127.0.0.1:9000/api/users/1/gitcredentials")
break
case "3", "PUT", "put":
utils.HighlightPrint("PUT Command:")
utils.SuccessPrint(`curl -X PUT http://127.0.0.1:9000/api/users/1/gitcredentials/11 -d '{"name":"test-credential-11","username":"cred11", "password":"cred11"}' -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOjEsInNjb3BlIjoiZGVmYXVsdCIsImZvcmNlQ2hhbmdlUGFzc3dvcmQiOmZhbHNlLCJleHAiOjE2NTcwODQ5MzUsImlhdCI6MTY1NzA1NjEzNX0.kUhkhhSt4WH33Q3hYzLwsYDv1a9a2ygCi6p8MkKMbwc'`)
break
case "4", "DELETE", "delete":
utils.HighlightPrint("DELETE Command:")
utils.SuccessPrint(`curl -X DELETE http://192.168.1.109:9000/api/users/1/gitcredentials/1 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsInJvbGUiOjEsInNjb3BlIjoiZGVmYXVsdCIsImZvcmNlQ2hhbmdlUGFzc3dvcmQiOmZhbHNlLCJleHAiOjE2NTQ3NTc1NzYsImlhdCI6MTY1NDcyODc3Nn0.GlxGmL6XTTH29Ns8aRnX5qp1qBfDVF2zaPzuSmG7qUs'`)
break
default:
return fmt.Errorf("No option %v\n", option)
}
return nil
}
func (task *CurlLookupTask) String() string {
return "Lookup Curl Commands"
}

18
go/tasks/exit.go Normal file
View File

@ -0,0 +1,18 @@
package tasks
import "errors"
type ExitTask struct {
}
func NewExitTask() *ExitTask {
return &ExitTask{}
}
func (task *ExitTask) Execute() error {
return errors.New("exit")
}
func (task *ExitTask) String() string {
return "Exit"
}

View File

@ -53,5 +53,5 @@ func (task *GenerateJwtTokenTask) Execute() error {
} }
func (task *GenerateJwtTokenTask) String() string { func (task *GenerateJwtTokenTask) String() string {
return "Generate JWT token" return "Generate JWT Token"
} }

View File

@ -1,6 +1,53 @@
package tasks package tasks
import (
"fmt"
"ocl/portainer-devtool/utils"
"os"
"strconv"
)
type Tasker interface { type Tasker interface {
Execute() error Execute() error
String() string String() string
} }
// ListCommandMenu iterates task items to display them // on the screen as the menu options
func ListCommandMenu(taskItems []Tasker, menuDesp string) error {
for {
printMainMenu := func() {
taskNames := []string{}
for _, task := range taskItems {
taskNames = append(taskNames, task.String())
}
utils.PrintMenu(menuDesp, taskNames)
// utils.MenuPrint("Which repository or action do you want to operate:", `
// 1. Portainer EE Repository
// 2. Portainer CE Repository
// 3. Portainer Agent Repository
// 4. Others
// 5. Quit`)
}
option := utils.SelectMenuItem(printMainMenu)
index, err := strconv.Atoi(option)
if err != nil {
utils.ErrorPrint("please type the option number\n")
continue
}
if index < 1 || index > len(taskItems) {
utils.ErrorPrint(fmt.Sprintf("no such option %s, please select again\n", option))
continue
}
err = taskItems[index-1].Execute()
if err != nil {
utils.ErrorPrint(err.Error())
os.Exit(1)
}
}
}

View File

@ -2,7 +2,6 @@ package utils
import ( import (
"fmt" "fmt"
"ocl/portainer-devtool/tasks"
) )
const ( const (
@ -40,19 +39,23 @@ func ErrorPrint(message string) {
} }
func InputPrint(message string) { func InputPrint(message string) {
// adding \n before setting colorful output can
// remove the first space in the colorful output
fmt.Println() fmt.Println()
fmt.Println(colorYellow, message, colorReset) fmt.Println(colorYellow, message, colorReset)
} }
func PrintMenu(question string, tasks []tasks.Tasker) { func PrintMenu(question string, taskNames []string) {
if question != "" { if question != "" {
InputPrint(fmt.Sprintf("[%s]", question)) InputPrint(fmt.Sprintf("[%s]", question))
} }
menuContent := "" // adding \n before setting colorful output can
// remove the first space in the colorful output
menuContent := "\n"
for i, task := range tasks { for i, name := range taskNames {
menuContent += fmt.Sprintf("%d. %s\n", i+1, task.String()) menuContent += fmt.Sprintf("%d. %s\n", i+1, name)
} }
fmt.Println(colorCyan, menuContent, colorReset) fmt.Println(colorCyan, menuContent, colorReset)