From 6560a6c86a50c15bcca5b9ba55a800611c81cd74 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Sat, 4 Dec 2021 16:57:18 -0500 Subject: [PATCH 01/25] feat: begin work on validator Co-authored-by: fishingchampion@gmail.com --- grpc/agent/agent.go | 75 ++++++++++++++++++++++++++++++++++++ grpc/agent/agent_unix.go | 63 ++++++++++++++++++++++++++++-- grpc/agent/agent_windows.go | 28 ++++++++++++++ grpc/proto/agent_proto.proto | 3 +- 4 files changed, 164 insertions(+), 5 deletions(-) diff --git a/grpc/agent/agent.go b/grpc/agent/agent.go index 9443e639..1a820ab0 100644 --- a/grpc/agent/agent.go +++ b/grpc/agent/agent.go @@ -224,6 +224,81 @@ func RequestTask(c pb.LaforgeClient) { md5hash := taskArgs[1] taskerr := ValidateMD5Hash(filepath, md5hash) RequestTaskStatusRequest(taskerr, clientID, c) + case pb.TaskReply_VALIDATOR: // new agent command type processing + taskArgs := strings.Split(r.Args, ",") + // example validator string + // validation_name, + validatorName := taskArgs[0] + var validationArgs []string + if len(taskArgs) > 1 { + validationArgs = taskArgs[1:] + } + switch validatorName { + case "net-banner": + fmt.Println("hi") + case "win-registry-hive": + fmt.Println("hi") + case "win-netbios-ping": + fmt.Println("hi") + case "host-ip-config": + fmt.Println("hi") + case "host-in-subnet": + fmt.Println("hi") + case "host-ntp-server": + fmt.Println("hi") + case "linux-apt-installed": + fmt.Println("hi") + case "linux-yum-installed": + fmt.Println("hi") + case "linux-ssh-key-authorized": + fmt.Println("hi") + case "linux-apparmor": + fmt.Println("hi") + case "linux-selinux": + fmt.Println("hi") + case "net-tcp-open": + fmt.Println("hi") + case "net-udp-open": + fmt.Println("hi") + case "net-http-content-regex": + fmt.Println("hi") + case "file-exists": + fmt.Println("hi") + case "file-hash": + fmt.Println("hi") + case "file-content-regex": + fmt.Println("hi") + case "dir-exists": + fmt.Println("hi") + case "user-exists": + fmt.Println("hi") + case "user-group-membership": + fmt.Println("hi") + case "host-port-open": + fmt.Println("hi") + case "host-process-running": + fmt.Println("hi") + case "host-service-state": + fmt.Println("hi") + case "net-icmp": + fmt.Println("hi") + case "net-http-content-hash": + fmt.Println("hi") + case "file-content-string": + fmt.Println("hi") + case "file-permission": + fmt.Println("hi") + case "win-registry-setting": + fmt.Println("hi") + case "win-domain-membership": + fmt.Println("hi") + case "host-firewall-port": + fmt.Println("hi") + case "log-match": + fmt.Println("hi") + + } + default: logger.Infof("Response Message: %v", r) RequestTaskStatusRequest(nil, clientID, c) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index 32204866..7da2deb6 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -3,13 +3,22 @@ package main import ( + "crypto/md5" "fmt" "io" + "io/ioutil" + "log" + "net/http" + s "os" "os/exec" os "os/user" "syscall" ) +func MD5Sum(content string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(content))) +} + // RebootSystem Reboots Host Operating System func RebootSystem() { syscall.Sync() @@ -20,7 +29,7 @@ func RebootSystem() { func CreateSystemUser(username string, password string) error { _, err := os.Lookup(username) if err != nil { - ExecuteCommand("useradd", username) + // ExecuteCommand("useradd", username) ChangeSystemUserPassword(username, password) } return nil @@ -31,7 +40,7 @@ func ChangeSystemUserPassword(username string, password string) error { cmd := exec.Command("passwd", username) stdin, err := cmd.StdinPipe() if err != nil { - logger.Error(err) + // logger.Error(err) } defer stdin.Close() @@ -40,7 +49,7 @@ func ChangeSystemUserPassword(username string, password string) error { io.WriteString(stdin, passnew) if err = cmd.Start(); err != nil { - logger.Errorf("An error occured: ", err) + // logger.Errorf("An error occured: ", err) } cmd.Wait() @@ -50,6 +59,52 @@ func ChangeSystemUserPassword(username string, password string) error { // AddSystemUserGroup Change user password. func AddSystemUserGroup(groupname string, username string) error { - ExecuteCommand("usermod", "-a", "-G", groupname, username) + // ExecuteCommand("usermod", "-a", "-G", groupname, username) return nil } + +// Validation functions +func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) + return true, nil +} + +func NetHttpContentRegex(full_url string) (string, error) { + net_resp, err := http.Get(full_url) + if err != nil { + return "", err + } + defer net_resp.Body.Close() + page_html, deserialize_err := ioutil.ReadAll(net_resp.Body) + if deserialize_err != nil { + return "", deserialize_err + } + + return MD5Sum(fmt.Sprintf("%s", page_html)), nil +} + +func FileExists(file_location string) (bool, error) { // exists (boolean) + stat_info, read_err := s.Stat(file_location) + if read_err != nil { + return false, read_err + } + return !stat_info.IsDir(), nil +} + +func FileHash(file_location string) (string, error) { // exists (boolean) + file_read, read_err := s.Open(file_location) + if read_err != nil { + return "", read_err + } + file_hash := md5.New() + if _, err := io.Copy(file_hash, file_read); err != nil { + log.Fatal(err) + } + return fmt.Sprintf("%x", file_hash.Sum(nil)), nil +} + +func main() { + fmt.Println("wew") + // fmt.Println(NetHttpContentRegex("https://vcu.edu")) + // fmt.Println(FileExists("/home/piero/most-coding-stuff/laforge/validations")) + fmt.Println(FileHash("/home/piero/most-coding-stuff/laforge/validations/test_file.txt")) +} diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 3a6c4ee6..039844f3 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -1,8 +1,11 @@ +//go:build windows // +build windows package main import ( + "fmt" + s "os" "syscall" wapi "github.com/iamacarpet/go-win64api" @@ -39,3 +42,28 @@ func AddSystemUserGroup(groupname string, username string) error { _, err := wapi.LocalGroupAddMembers(groupname, []string{username}) return err } + +// Validate file system + +// Validation functions +func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) + return true, nil +} + +func NetHttpContentRegex(full_url string) (string, error) { + + return "false", nil +} + +func FileExists(file_location string) (bool, error) { + stat_info, read_err := s.Stat(file_location) + if read_err != nil { + return false, read_err + } + return !stat_info.IsDir(), nil +} + +func main() { + fmt.Println("windows") + fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) +} diff --git a/grpc/proto/agent_proto.proto b/grpc/proto/agent_proto.proto index f5bcb274..1a008910 100644 --- a/grpc/proto/agent_proto.proto +++ b/grpc/proto/agent_proto.proto @@ -54,7 +54,8 @@ message TaskReply { CREATEUSERPASS = 6; ADDTOGROUP = 7; EXECUTE = 8; - VALIDATE = 9; + VALIDATE = 9; // for checking md5 hash only + VALIDATOR = 10; // validation task } Command command = 2; string args = 3; From ad8a8b8d5322a1162ac463d78a0fade5a05ab1ad Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Sat, 4 Dec 2021 16:57:18 -0500 Subject: [PATCH 02/25] feat: restart branch with upstream changes --- grpc/agent/agent.go | 74 ++++++++++++++++++++++++++++++++++++ grpc/agent/agent_unix.go | 62 ++++++++++++++++++++++++++++-- grpc/agent/agent_windows.go | 27 +++++++++++++ grpc/proto/agent_proto.proto | 1 + 4 files changed, 160 insertions(+), 4 deletions(-) diff --git a/grpc/agent/agent.go b/grpc/agent/agent.go index 8b8cf1dc..b90aa777 100644 --- a/grpc/agent/agent.go +++ b/grpc/agent/agent.go @@ -260,6 +260,80 @@ func RequestTask(c pb.LaforgeClient) { content := strings.ReplaceAll(taskArgs[1], "🔥", "\n") taskerr := AppendFile(path, content) RequestTaskStatusRequest("", taskerr, r.Id, c) + case pb.TaskReply_VALIDATOR: // new agent command type processing + taskArgs := strings.Split(r.Args, ",") + // example validator string + // validation_name, + validatorName := taskArgs[0] + var validationArgs []string + if len(taskArgs) > 1 { + validationArgs = taskArgs[1:] + } + switch validatorName { + case "net-banner": + fmt.Println("hi") + case "win-registry-hive": + fmt.Println("hi") + case "win-netbios-ping": + fmt.Println("hi") + case "host-ip-config": + fmt.Println("hi") + case "host-in-subnet": + fmt.Println("hi") + case "host-ntp-server": + fmt.Println("hi") + case "linux-apt-installed": + fmt.Println("hi") + case "linux-yum-installed": + fmt.Println("hi") + case "linux-ssh-key-authorized": + fmt.Println("hi") + case "linux-apparmor": + fmt.Println("hi") + case "linux-selinux": + fmt.Println("hi") + case "net-tcp-open": + fmt.Println("hi") + case "net-udp-open": + fmt.Println("hi") + case "net-http-content-regex": + fmt.Println("hi") + case "file-exists": + fmt.Println("hi") + case "file-hash": + fmt.Println("hi") + case "file-content-regex": + fmt.Println("hi") + case "dir-exists": + fmt.Println("hi") + case "user-exists": + fmt.Println("hi") + case "user-group-membership": + fmt.Println("hi") + case "host-port-open": + fmt.Println("hi") + case "host-process-running": + fmt.Println("hi") + case "host-service-state": + fmt.Println("hi") + case "net-icmp": + fmt.Println("hi") + case "net-http-content-hash": + fmt.Println("hi") + case "file-content-string": + fmt.Println("hi") + case "file-permission": + fmt.Println("hi") + case "win-registry-setting": + fmt.Println("hi") + case "win-domain-membership": + fmt.Println("hi") + case "host-firewall-port": + fmt.Println("hi") + case "log-match": + fmt.Println("hi") + + } default: logger.Infof("Response Message: %v", r) RequestTaskStatusRequest("", nil, r.Id, c) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index 36dcdba4..64bf2b36 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -3,10 +3,14 @@ package main import ( + "crypto/md5" "fmt" "io" + "io/ioutil" + "log" "net/http" "os" + s "os" "os/exec" "os/user" "path/filepath" @@ -14,6 +18,10 @@ import ( "time" ) +func MD5Sum(content string) string { + return fmt.Sprintf("%x", md5.Sum([]byte(content))) +} + // RebootSystem Reboots Host Operating System func RebootSystem() { syscall.Sync() @@ -26,7 +34,7 @@ func RebootSystem() { func CreateSystemUser(username string, password string) error { _, err := user.Lookup(username) if err != nil { - ExecuteCommand("useradd", username) + // ExecuteCommand("useradd", username) ChangeSystemUserPassword(username, password) } return nil @@ -37,7 +45,7 @@ func ChangeSystemUserPassword(username string, password string) error { cmd := exec.Command("passwd", username) stdin, err := cmd.StdinPipe() if err != nil { - logger.Error(err) + // logger.Error(err) } defer stdin.Close() @@ -46,7 +54,7 @@ func ChangeSystemUserPassword(username string, password string) error { io.WriteString(stdin, passnew) if err = cmd.Start(); err != nil { - logger.Errorf("An error occured: ", err) + // logger.Errorf("An error occured: ", err) } cmd.Wait() @@ -56,7 +64,7 @@ func ChangeSystemUserPassword(username string, password string) error { // AddSystemUserGroup Change user password. func AddSystemUserGroup(groupname string, username string) error { - ExecuteCommand("usermod", "-a", "-G", groupname, username) + // ExecuteCommand("usermod", "-a", "-G", groupname, username) return nil } @@ -157,3 +165,49 @@ func GetSystemDependencies() []string { "Requires=network.target", "After=network-online.target"} } + +// Validation functions +func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) + return true, nil +} + +func NetHttpContentRegex(full_url string) (string, error) { + net_resp, err := http.Get(full_url) + if err != nil { + return "", err + } + defer net_resp.Body.Close() + page_html, deserialize_err := ioutil.ReadAll(net_resp.Body) + if deserialize_err != nil { + return "", deserialize_err + } + + return MD5Sum(fmt.Sprintf("%s", page_html)), nil +} + +func FileExists(file_location string) (bool, error) { // exists (boolean) + stat_info, read_err := s.Stat(file_location) + if read_err != nil { + return false, read_err + } + return !stat_info.IsDir(), nil +} + +func FileHash(file_location string) (string, error) { // exists (boolean) + file_read, read_err := s.Open(file_location) + if read_err != nil { + return "", read_err + } + file_hash := md5.New() + if _, err := io.Copy(file_hash, file_read); err != nil { + log.Fatal(err) + } + return fmt.Sprintf("%x", file_hash.Sum(nil)), nil +} + +func main() { // driver for tests, main function not necessary later + fmt.Println("wew") + // fmt.Println(NetHttpContentRegex("https://vcu.edu")) + // fmt.Println(FileExists("/home/piero/most-coding-stuff/laforge/validations")) + fmt.Println(FileHash("/home/piero/most-coding-stuff/laforge/validations/test_file.txt")) +} diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 0eb7530f..5ec23a34 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -4,9 +4,11 @@ package main import ( + "fmt" "io" "net/http" "os" + s "os" "os/exec" "path/filepath" "strings" @@ -130,3 +132,28 @@ func SystemExecuteCommand(command string, args ...string) (string, error) { func GetSystemDependencies() []string { return []string{} } + +// Validate file system + +// Validation functions +func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) + return true, nil +} + +func NetHttpContentRegex(full_url string) (string, error) { + + return "false", nil +} + +func FileExists(file_location string) (bool, error) { + stat_info, read_err := s.Stat(file_location) + if read_err != nil { + return false, read_err + } + return !stat_info.IsDir(), nil +} + +func main() { + fmt.Println("windows") + fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) +} diff --git a/grpc/proto/agent_proto.proto b/grpc/proto/agent_proto.proto index 54f7b7e7..6dd7c16d 100644 --- a/grpc/proto/agent_proto.proto +++ b/grpc/proto/agent_proto.proto @@ -57,6 +57,7 @@ message TaskReply { VALIDATE = 9; CHANGEPERMS = 10; APPENDFILE = 11; + VALIDATOR = 12; // validation task } Command command = 2; string args = 3; From ca6f0b19db02a8352a926942c4f848bf826083f1 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 29 Dec 2021 13:55:43 -0500 Subject: [PATCH 03/25] add some more validations --- grpc/agent/agent_unix.go | 109 ++++++++++++++++++++++++++++++++- grpc/agent/agent_windows.go | 117 +++++++++++++++++++++++++++++++++++- grpc/server/server.go | 4 ++ 3 files changed, 227 insertions(+), 3 deletions(-) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index b6fb45ea..34c53f54 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -8,12 +8,14 @@ import ( "io" "io/ioutil" "log" + "net" "net/http" "os" s "os" "os/exec" "os/user" "path/filepath" + "strings" "syscall" "time" ) @@ -182,7 +184,8 @@ func NetHttpContentRegex(full_url string) (string, error) { return "", deserialize_err } - return MD5Sum(fmt.Sprintf("%s", page_html)), nil + // return MD5Sum(fmt.Sprintf("%s", page_html)), nil + return string(page_html[:]), nil // stringify } func FileExists(file_location string) (bool, error) { // exists (boolean) @@ -193,7 +196,7 @@ func FileExists(file_location string) (bool, error) { // exists (boolean) return !stat_info.IsDir(), nil } -func FileHash(file_location string) (string, error) { // exists (boolean) +func FileHash(file_location string) (string, error) { // hash of the file (string) file_read, read_err := s.Open(file_location) if read_err != nil { return "", read_err @@ -205,6 +208,108 @@ func FileHash(file_location string) (string, error) { // exists (boolean) return fmt.Sprintf("%x", file_hash.Sum(nil)), nil } +func FileContentRegex(file_location string) (string, error) { // page content to be returned and checked serverside (string) + file_read, read_err := s.Open(file_location) + if read_err != nil { + return "", read_err + } + file_hash := md5.New() + if body_contents, err := io.Copy(file_hash, file_read); err != nil { + log.Fatal(err) + } + return body_contents, nil +} + +func DirectoryExists(directory string) (bool, error) { // exists (boolean) + stat_info, read_err := s.Stat(directory) + if read_err != nil { + return false, read_err + } + return stat_info.IsDir(), nil +} + +func UserExists(user_name string) (bool, error) { // exists (boolean) + passwd_contents, read_err := ioutil.ReadFile("/etc/passwd") + if read_err != nil { + return false, read_err + } + passwd_text := strings.Split(string(passwd_contents), "\n") + for i := 0; i < len(passwd_text); i++ { + if strings.HasPrefix(passwd_text[i], user_name) { + return true, nil + } + } + return false, nil +} + +func UserGroupMember(user_name string, group_name string) (bool, error) { // is in the group or not (boolean) + group_contents, read_err := ioutil.ReadFile("/etc/group") + if read_err != nil { + return false, read_err + } + groups := strings.Split(string(group_contents), "\n") + for i := 0; i < len(groups); i++ { + // example groups + /* + adm:x:4:piero + tty:x:5: + disk:x:6: + lp:x:7: + mail:x:8: + news:x:9: + uucp:x:10: + man:x:12: + proxy:x:13: + kmem:x:15: + dialout:x:20: + fax:x:21: + voice:x:22: + cdrom:x:24:piero + */ + group_line_chunks := strings.Split(string(group_contents), ":") + if group_line_chunks[0] == group_name && len(group_line_chunks) > 3 { + // first part of /etc/group entry matches and there are users assigned to the group + users_in_group := strings.Split(group_line_chunks[3], ",") + for j := 0; j < len(users_in_group); j++ { + if users_in_group[j] == user_name { + return true, nil + } + } + } + return false, nil + } + return false, nil +} + +// https://stackoverflow.com/questions/56336168/golang-check-tcp-port-open +func HostPortOpen(port int64) (bool, error) { // exists (boolean) + conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", string(port)), time.Second) + if err != nil { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func HostProcessRunning(process_name string) (bool, error) { // running (boolean) + result := exec.Command("sh", "ps", "-a") + ps_output, err := result.Output() + if err != nil { + return false, err + } + ps_lines := strings.Split(string(ps_output), "\n") + for i := 0; i < len(ps_lines); i++ { + if strings.HasSuffix(ps_lines[i], process_name) { + return true, nil + } + } + return false, nil +} + func main() { fmt.Println("wew") // fmt.Println(NetHttpContentRegex("https://vcu.edu")) diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 5ec23a34..dbbf29d0 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -1,7 +1,7 @@ //go:build windows // +build windows -package main +// package main import ( "fmt" @@ -153,6 +153,121 @@ func FileExists(file_location string) (bool, error) { return !stat_info.IsDir(), nil } +func FileHash(file_location string) (string, error) { // hash of the file (string) + file_read, read_err := s.Open(file_location) + if read_err != nil { + return "", read_err + } + file_hash := md5.New() + if _, err := io.Copy(file_hash, file_read); err != nil { + log.Fatal(err) + } + return fmt.Sprintf("%x", file_hash.Sum(nil)), nil +} + +func FileContentRegex(file_location string) (string, error) { // page content to be returned and checked serverside (string) + file_read, read_err := s.Open(file_location) + if read_err != nil { + return "", read_err + } + file_hash := md5.New() + if body_contents, err := io.Copy(file_hash, file_read); err != nil { + log.Fatal(err) + } + return body_contents, nil +} + +func DirectoryExists(directory string) (bool, error) { // exists (boolean) + stat_info, read_err := s.Stat(directory) + if read_err != nil { + return false, read_err + } + return stat_info.IsDir(), nil +} + +func UserExists(user_name string) (bool, error) { // exists (boolean + users, err := wapi.ListLocalUsers() + if err != nil { + return false, err + } + for _, user := range users { + if u.Username == user_name { + return true, nil + } + } + return false, nil +} + +func UserGroupMember(user_name string, group_name string) (bool, error) { // is in the group or not (boolean) + // TODO: need a special way to get this via windows + // group_contents, read_err := ioutil.ReadFile("/etc/group") + if read_err != nil { + return false, read_err + } + groups := strings.Split(string(group_contents), "\n") + for i := 0; i < len(groups); i++ { + // example groups + /* + adm:x:4:piero + tty:x:5: + disk:x:6: + lp:x:7: + mail:x:8: + news:x:9: + uucp:x:10: + man:x:12: + proxy:x:13: + kmem:x:15: + dialout:x:20: + fax:x:21: + voice:x:22: + cdrom:x:24:piero + */ + group_line_chunks := strings.Split(string(group_contents), ":") + if group_line_chunks[0] == group_name && len(group_line_chunks) > 3 { + // first part of /etc/group entry matches and there are users assigned to the group + users_in_group := strings.Split(group_line_chunks[3], ",") + for j := 0; j < len(users_in_group); j++ { + if users_in_group[j] == user_name { + return true, nil + } + } + } + return false, nil + } + return false, nil +} + +// https://stackoverflow.com/questions/56336168/golang-check-tcp-port-open +func HostPortOpen(port int64) (bool, error) { // exists (boolean) + conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", string(port)), time.Second) + if err != nil { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func HostProcessRunning(process_name string) (bool, error) { // running (boolean) + // TODO: add specific logic for windows + // result := exec.Command("sh", "ps", "-a") + ps_output, err := result.Output() + if err != nil { + return false, err + } + ps_lines := strings.Split(string(ps_output), "\n") + for i := 0; i < len(ps_lines); i++ { + if strings.HasSuffix(ps_lines[i], process_name) { + return true, nil + } + } + return false, nil +} + func main() { fmt.Println("windows") fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) diff --git a/grpc/server/server.go b/grpc/server/server.go index 40b2cb36..c0890051 100644 --- a/grpc/server/server.go +++ b/grpc/server/server.go @@ -9,6 +9,7 @@ import ( "github.com/gen0cide/laforge/ent" "github.com/gen0cide/laforge/ent/agenttask" + "github.com/gen0cide/laforge/ent/command" "github.com/gen0cide/laforge/ent/provisionedhost" pb "github.com/gen0cide/laforge/grpc/proto" "github.com/go-redis/redis/v8" @@ -198,6 +199,9 @@ func (s *Server) InformTaskStatus(ctx context.Context, in *pb.TaskStatusRequest) return &pb.TaskStatusReply{Status: "ERROR"}, nil } output := strings.ReplaceAll(in.GetOutput(), "🔥", "\n") + // server-side validation hook starting + agent_command, err := s.Client.Command.Query().Where(command.IDEQ(uuid)).First(ctx) + err = entAgentTask.Update(). SetState(agenttask.State(in.GetStatus())). SetErrorMessage(in.GetErrorMessage()). From 0f646060b9ae97a2e857a865eadfabcb04c3b035 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Tue, 18 Jan 2022 19:59:33 -0500 Subject: [PATCH 04/25] feat: almost all unix agent validations written --- grpc/agent/agent_unix.go | 132 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 122 insertions(+), 10 deletions(-) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index 34c53f54..fb356320 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -1,3 +1,4 @@ +//go:build unix || linux // +build unix linux package main @@ -15,6 +16,7 @@ import ( "os/exec" "os/user" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -173,7 +175,7 @@ func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) return true, nil } -func NetHttpContentRegex(full_url string) (string, error) { +func NetHttpContentRegex(full_url string) (string, error) { // content hash (string) net_resp, err := http.Get(full_url) if err != nil { return "", err @@ -214,10 +216,11 @@ func FileContentRegex(file_location string) (string, error) { // page content to return "", read_err } file_hash := md5.New() - if body_contents, err := io.Copy(file_hash, file_read); err != nil { + _, err := io.Copy(file_hash, file_read) + if err != nil { log.Fatal(err) } - return body_contents, nil + return fmt.Sprintf("%x", file_hash.Sum(nil)), nil } func DirectoryExists(directory string) (bool, error) { // exists (boolean) @@ -266,7 +269,7 @@ func UserGroupMember(user_name string, group_name string) (bool, error) { // is voice:x:22: cdrom:x:24:piero */ - group_line_chunks := strings.Split(string(group_contents), ":") + group_line_chunks := strings.Split(groups[i], ":") if group_line_chunks[0] == group_name && len(group_line_chunks) > 3 { // first part of /etc/group entry matches and there are users assigned to the group users_in_group := strings.Split(group_line_chunks[3], ",") @@ -276,14 +279,14 @@ func UserGroupMember(user_name string, group_name string) (bool, error) { // is } } } - return false, nil } return false, nil } // https://stackoverflow.com/questions/56336168/golang-check-tcp-port-open func HostPortOpen(port int64) (bool, error) { // exists (boolean) - conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", string(port)), time.Second) + + conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port))), 10*time.Second) if err != nil { return false, err } @@ -296,7 +299,7 @@ func HostPortOpen(port int64) (bool, error) { // exists (boolean) } func HostProcessRunning(process_name string) (bool, error) { // running (boolean) - result := exec.Command("sh", "ps", "-a") + result := exec.Command("ps", "-a") ps_output, err := result.Output() if err != nil { return false, err @@ -310,9 +313,118 @@ func HostProcessRunning(process_name string) (bool, error) { // running (boolean return false, nil } +// Adapted from https://stackoverflow.com/questions/48263281/how-to-find-sshd-service-status-in-golang +func HostServiceState(service_name string) (string, error) { + // returned status is one of the following: + // active | inactive | enabled | disabled | static | masked | alias | linked + // https://www.cyberciti.biz/faq/systemd-systemctl-view-status-of-a-service-on-linux/ lists all possibilities and meanings + cmd := exec.Command("systemctl", "check", "sshd") // ASSUMPTION: the computer uses systemd + out, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + return string(out), nil +} + +func LinuxAPTInstalled(package_name string) (bool, error) { // installed + result := exec.Command("apt", "-qq", "list", package_name) + ps_output, err := result.Output() + if err != nil { + return false, err + } + apt_lines := strings.Split(string(ps_output), "\n") + for i := 0; i < len(apt_lines); i++ { + if strings.HasPrefix(apt_lines[i], package_name) && (strings.HasSuffix(apt_lines[i], "[installed]") || strings.HasSuffix(apt_lines[i], "[installed,local]") || strings.HasSuffix(apt_lines[i], "[installed,automatic]")) { + return true, nil + } + } + return false, nil +} + +func NetTCPOpen(ip string, port int) (bool, error) { // exists (boolean) + // net.Dial or net.DialTimeout will succeed if the following succeeds: + /* + Client -> Server: SYN + Server -> Client: SYN-ACK + Client -> Server: ACK + */ + conn, err := net.DialTimeout("tcp", net.JoinHostPort(ip, strconv.Itoa(port)), 10*time.Second) + if err != nil && !strings.HasSuffix(err.Error(), "connection refused") { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func NetUDPOpen(ip string, port int) (bool, error) { // exists (boolean) + conn, err := net.DialTimeout("udp", net.JoinHostPort(ip, strconv.Itoa(port)), 10*time.Second) + // we don't really know if a udp connection is alive or not, so + if err != nil { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func NetICMP(ip string) (bool, error) { // responded (boolean) + // This WILL block the thread! However, agent tasks are on their own threads. + result := exec.Command("ping", "-c", "5", ip) // you can write a ping packet and send it using pure golang, however it's quite complicated and requires more importing of libraries + ps_output, err := result.Output() + if err != nil { + return false, err + } + fmt.Println(string(ps_output)) + ps_lines := strings.Split(string(ps_output), "\n") + for i := 0; i < len(ps_lines); i++ { + if strings.HasPrefix(ps_lines[i], "5 packets transmitted, 5 received") { // this is pretty jank + return true, nil + } + } + return false, nil +} + +func FileContentString(filepath string, text string) (bool, error) { // matches + file_contents, read_err := ioutil.ReadFile(filepath) + if read_err != nil { + return false, read_err + } + lines := strings.Split(string(file_contents), "\n") + for i := 0; i < len(lines); i++ { + if strings.Contains(lines[i], text) { + return true, nil + } + } + return false, nil +} + +// https://stackoverflow.com/questions/45429210/how-do-i-check-a-files-permissions-in-linux-using-go +func FilePermission(filepath string) (string, error) { // permissions (in the form of SRWXRWXRWX, where S is setuid bit) + info, err := os.Stat(filepath) + if err != nil { + return "", err + } + return info.Mode().String(), nil +} + func main() { - fmt.Println("wew") // fmt.Println(NetHttpContentRegex("https://vcu.edu")) - // fmt.Println(FileExists("/home/piero/most-coding-stuff/laforge/validations")) - fmt.Println(FileHash("/home/piero/most-coding-stuff/laforge/validations/test_file.txt")) + // fmt.Println(FileExists("/home/piero/most-coding-stuff/laforge/test_file")) // change to dir, won't get tripped up + // fmt.Println(FileHash("/home/piero/most-coding-stuff/laforge/test_file.txt")) + // fmt.Println(UserGroupMember("piero", "wew")) + // fmt.Println(HostPortOpen(8080)) + // fmt.Println(HostProcessRunning("nginx")) + // fmt.Println(HostServiceState("nginx")) + // fmt.Println(LinuxAPTInstalled("wget")) + // fmt.Println(NetTCPOpen("127.0.0.1", 80)) // test with nginx for ease + // fmt.Println(NetICMP("192.168.1.255")) + // fmt.Println(FileContentString("/home/piero/most-coding-stuff/laforge/test_file.txt", "hi")) + // fmt.Println(FilePermission("/home/piero/most-coding-stuff/laforge/test_file.txt")) } From bbb39bf60531b559292b992a365fb7b6d40e30b1 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Tue, 18 Jan 2022 21:49:39 -0500 Subject: [PATCH 05/25] feat: some windows validations + able to "go run" --- grpc/agent/agent_windows.go | 170 +++++++++++++++++++++++++----------- 1 file changed, 120 insertions(+), 50 deletions(-) diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index dbbf29d0..74c08257 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -1,16 +1,23 @@ -//go:build windows +windows // +build windows -// package main +package p +// package main // uncomment for testing funcs below import ( + "crypto/md5" "fmt" "io" + "io/ioutil" + "log" + "net" "net/http" "os" s "os" "os/exec" + user "os/user" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -28,7 +35,7 @@ func RebootSystem() { r1, _, _ := exitwin.Call(0x02, 0) if r1 != 1 { - ExecuteCommand("cmd", "/C", "shutdown", "/r", "/f") + SystemExecuteCommand("cmd", "/C", "shutdown", "/r", "/f") } time.Sleep(1 * time.Hour) // sleep forever bc we need to restart @@ -133,16 +140,24 @@ func GetSystemDependencies() []string { return []string{} } -// Validate file system - // Validation functions func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) return true, nil } -func NetHttpContentRegex(full_url string) (string, error) { +func NetHttpContentRegex(full_url string) (string, error) { // content hash (string) + net_resp, err := http.Get(full_url) + if err != nil { + return "", err + } + defer net_resp.Body.Close() + page_html, deserialize_err := ioutil.ReadAll(net_resp.Body) + if deserialize_err != nil { + return "", deserialize_err + } - return "false", nil + // return MD5Sum(fmt.Sprintf("%s", page_html)), nil + return string(page_html[:]), nil // stringify } func FileExists(file_location string) (bool, error) { @@ -171,10 +186,11 @@ func FileContentRegex(file_location string) (string, error) { // page content to return "", read_err } file_hash := md5.New() - if body_contents, err := io.Copy(file_hash, file_read); err != nil { + _, err := io.Copy(file_hash, file_read) + if err != nil { log.Fatal(err) } - return body_contents, nil + return fmt.Sprintf("%x", file_hash.Sum(nil)), nil } func DirectoryExists(directory string) (bool, error) { // exists (boolean) @@ -190,8 +206,9 @@ func UserExists(user_name string) (bool, error) { // exists (boolean if err != nil { return false, err } + fmt.Println(users) for _, user := range users { - if u.Username == user_name { + if user.Username == user_name { return true, nil } } @@ -199,48 +216,15 @@ func UserExists(user_name string) (bool, error) { // exists (boolean } func UserGroupMember(user_name string, group_name string) (bool, error) { // is in the group or not (boolean) - // TODO: need a special way to get this via windows - // group_contents, read_err := ioutil.ReadFile("/etc/group") - if read_err != nil { - return false, read_err - } - groups := strings.Split(string(group_contents), "\n") - for i := 0; i < len(groups); i++ { - // example groups - /* - adm:x:4:piero - tty:x:5: - disk:x:6: - lp:x:7: - mail:x:8: - news:x:9: - uucp:x:10: - man:x:12: - proxy:x:13: - kmem:x:15: - dialout:x:20: - fax:x:21: - voice:x:22: - cdrom:x:24:piero - */ - group_line_chunks := strings.Split(string(group_contents), ":") - if group_line_chunks[0] == group_name && len(group_line_chunks) > 3 { - // first part of /etc/group entry matches and there are users assigned to the group - users_in_group := strings.Split(group_line_chunks[3], ",") - for j := 0; j < len(users_in_group); j++ { - if users_in_group[j] == user_name { - return true, nil - } - } - } - return false, nil - } + fmt.Println(user.Lookup(user_name)) return false, nil } +// https://stackoverflow.com/questions/56336168/golang-check-tcp-port-open // https://stackoverflow.com/questions/56336168/golang-check-tcp-port-open func HostPortOpen(port int64) (bool, error) { // exists (boolean) - conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", string(port)), time.Second) + + conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(int(port))), 10*time.Second) if err != nil { return false, err } @@ -253,8 +237,7 @@ func HostPortOpen(port int64) (bool, error) { // exists (boolean) } func HostProcessRunning(process_name string) (bool, error) { // running (boolean) - // TODO: add specific logic for windows - // result := exec.Command("sh", "ps", "-a") + result := exec.Command("ps", "-a") ps_output, err := result.Output() if err != nil { return false, err @@ -268,7 +251,94 @@ func HostProcessRunning(process_name string) (bool, error) { // running (boolean return false, nil } +// Adapted from https://stackoverflow.com/questions/48263281/how-to-find-sshd-service-status-in-golang +func HostServiceState(service_name string) (string, error) { + // returned status is one of the following: + // active | inactive | enabled | disabled | static | masked | alias | linked + // https://www.cyberciti.biz/faq/systemd-systemctl-view-status-of-a-service-on-linux/ lists all possibilities and meanings + cmd := exec.Command("systemctl", "check", "sshd") // ASSUMPTION: the computer uses systemd + out, err := cmd.CombinedOutput() + if err != nil { + return "", err + } + return string(out), nil +} + +func NetTCPOpen(ip string, port int) (bool, error) { // exists (boolean) + // net.Dial or net.DialTimeout will succeed if the following succeeds: + /* + Client -> Server: SYN + Server -> Client: SYN-ACK + Client -> Server: ACK + */ + conn, err := net.DialTimeout("tcp", net.JoinHostPort(ip, strconv.Itoa(port)), 10*time.Second) + if err != nil && !strings.HasSuffix(err.Error(), "connection refused") { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func NetUDPOpen(ip string, port int) (bool, error) { // exists (boolean) + conn, err := net.DialTimeout("udp", net.JoinHostPort(ip, strconv.Itoa(port)), 10*time.Second) + // we don't really know if a udp connection is alive or not, so + if err != nil { + return false, err + } + if conn != nil { + defer conn.Close() // no hanging processes + return true, nil + } else { + return false, nil + } +} + +func NetICMP(ip string) (bool, error) { // responded (boolean) + // This WILL block the thread! However, agent tasks are on their own threads. + result := exec.Command("ping", "-c", "5", ip) // you can write a ping packet and send it using pure golang, however it's quite complicated and requires more importing of libraries + ps_output, err := result.Output() + if err != nil { + return false, err + } + fmt.Println(string(ps_output)) + ps_lines := strings.Split(string(ps_output), "\n") + for i := 0; i < len(ps_lines); i++ { + if strings.HasPrefix(ps_lines[i], "5 packets transmitted, 5 received") { // this is pretty jank + return true, nil + } + } + return false, nil +} + +func FileContentString(filepath string, text string) (bool, error) { // matches + file_contents, read_err := ioutil.ReadFile(filepath) + if read_err != nil { + return false, read_err + } + lines := strings.Split(string(file_contents), "\n") + for i := 0; i < len(lines); i++ { + if strings.Contains(lines[i], text) { + return true, nil + } + } + return false, nil +} + +// https://stackoverflow.com/questions/45429210/how-do-i-check-a-files-permissions-in-linux-using-go +func FilePermission(filepath string) (string, error) { // permissions (in the form of SRWXRWXRWX, where S is setuid bit) + info, err := os.Stat(filepath) + if err != nil { + return "", err + } + return info.Mode().String(), nil +} + func main() { fmt.Println("windows") - fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) + fmt.Println(UserExists("piero")) + // fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) } From 8e451a531bed97f5ee547af8047d7f3ee1fc4054 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Tue, 25 Jan 2022 12:29:14 -0500 Subject: [PATCH 06/25] feat: goroutine for udptest --- grpc/agent/agent_unix.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index fb356320..ff4a897b 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -4,6 +4,8 @@ package main import ( + "bufio" + "context" "crypto/md5" "fmt" "io" @@ -366,14 +368,25 @@ func NetUDPOpen(ip string, port int) (bool, error) { // exists (boolean) if err != nil { return false, err } - if conn != nil { - defer conn.Close() // no hanging processes + recv_chan := make(chan bool) + go UDPOpenTest(conn, recv_chan) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + select { + case <-recv_chan: return true, nil - } else { + case <-time.After(10 * time.Second): + return false, nil + case <-ctx.Done(): return false, nil } } +func UDPOpenTest(socket net.Conn, return_chan chan bool) { + bufio.NewReader(socket).ReadByte() + return_chan <- true +} + func NetICMP(ip string) (bool, error) { // responded (boolean) // This WILL block the thread! However, agent tasks are on their own threads. result := exec.Command("ping", "-c", "5", ip) // you can write a ping packet and send it using pure golang, however it's quite complicated and requires more importing of libraries @@ -427,4 +440,5 @@ func main() { // fmt.Println(NetICMP("192.168.1.255")) // fmt.Println(FileContentString("/home/piero/most-coding-stuff/laforge/test_file.txt", "hi")) // fmt.Println(FilePermission("/home/piero/most-coding-stuff/laforge/test_file.txt")) + fmt.Println(NetUDPOpen("127.0.0.1", 3000)) } From 2944a3756314f11bc6b3292bdb5b533e0f5f276c Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 26 Jan 2022 14:09:07 -0500 Subject: [PATCH 07/25] feat: allow optional payload udp test --- grpc/agent/agent_unix.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index ff4a897b..e4ec7637 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -4,7 +4,6 @@ package main import ( - "bufio" "context" "crypto/md5" "fmt" @@ -362,14 +361,14 @@ func NetTCPOpen(ip string, port int) (bool, error) { // exists (boolean) } } -func NetUDPOpen(ip string, port int) (bool, error) { // exists (boolean) +func NetUDPOpen(ip string, port int, open_socket_payload string) (bool, error) { // exists (boolean) conn, err := net.DialTimeout("udp", net.JoinHostPort(ip, strconv.Itoa(port)), 10*time.Second) // we don't really know if a udp connection is alive or not, so if err != nil { return false, err } recv_chan := make(chan bool) - go UDPOpenTest(conn, recv_chan) + go UDPOpenTest(conn, recv_chan, open_socket_payload) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() select { @@ -382,8 +381,9 @@ func NetUDPOpen(ip string, port int) (bool, error) { // exists (boolean) } } -func UDPOpenTest(socket net.Conn, return_chan chan bool) { - bufio.NewReader(socket).ReadByte() +func UDPOpenTest(socket net.Conn, return_chan chan bool, optional_payload string) { + socket.Write([]byte(optional_payload)) + socket.Read([]byte("")) return_chan <- true } @@ -440,5 +440,5 @@ func main() { // fmt.Println(NetICMP("192.168.1.255")) // fmt.Println(FileContentString("/home/piero/most-coding-stuff/laforge/test_file.txt", "hi")) // fmt.Println(FilePermission("/home/piero/most-coding-stuff/laforge/test_file.txt")) - fmt.Println(NetUDPOpen("127.0.0.1", 3000)) + fmt.Println(NetUDPOpen("127.0.0.1", 3000, "")) } From 562aaf8a480cdad597f683da5e08577116101b81 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 26 Jan 2022 14:45:41 -0500 Subject: [PATCH 08/25] feat: try to make two laforges work in one Co-authored-by: dileonk --- go.mod | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index f24335f2..a9d8858f 100755 --- a/go.mod +++ b/go.mod @@ -1,13 +1,13 @@ -module github.com/gen0cide/laforge +module main go 1.16 require ( + github.com/gen0cide/laforge v1.1.10-0.20220126190907-2944a3756314 entgo.io/contrib v0.0.0-20210510070807-19d2feb90dc4 entgo.io/ent v0.9.1 github.com/99designs/gqlgen v0.13.0 github.com/StackExchange/wmi v0.0.0-20210224194228-fe8f1750fd46 // indirect - github.com/UnnoTed/fileb0x v1.1.4 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 github.com/briandowns/formatifier v0.0.0-20150226010542-6d068a6ce63a @@ -18,7 +18,7 @@ require ( github.com/frankban/quicktest v1.13.0 // indirect github.com/gin-contrib/cors v1.3.1 github.com/gin-gonic/gin v1.7.1 - github.com/go-git/go-git/v5 v5.4.2 // indirect + github.com/go-git/go-git/v5 v5.4.2 github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-playground/validator/v10 v10.6.1 // indirect github.com/go-redis/redis/v8 v8.11.0 @@ -30,7 +30,6 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/hcl/v2 v2.10.0 - github.com/hedwigz/entviz v0.0.0-20211018071308-cbfafe399286 // indirect github.com/iamacarpet/go-win64api v0.0.0-20210311141720-fe38760bed28 github.com/iancoleman/strcase v0.1.3 github.com/jackc/pgproto3/v2 v2.0.7 // indirect @@ -58,7 +57,7 @@ require ( github.com/zclconf/go-cty v1.8.3 golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf golang.org/x/net v0.0.0-20210510120150-4163338589ed - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect google.golang.org/genproto v0.0.0-20210510173355-fb37daa5cd7a // indirect google.golang.org/grpc v1.37.1 From 5382c1a6b8bb042b20ed55afa2a5248af7ade4ea Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 26 Jan 2022 14:55:14 -0500 Subject: [PATCH 09/25] feat: revert gomod change --- go.mod | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a9d8858f..dca27fbc 100755 --- a/go.mod +++ b/go.mod @@ -1,9 +1,8 @@ -module main +module github.com/gen0cide/laforge go 1.16 require ( - github.com/gen0cide/laforge v1.1.10-0.20220126190907-2944a3756314 entgo.io/contrib v0.0.0-20210510070807-19d2feb90dc4 entgo.io/ent v0.9.1 github.com/99designs/gqlgen v0.13.0 From 628b5ec21b2efee5f5bc50b3d5b89c5f2f917dad Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 26 Jan 2022 15:20:20 -0500 Subject: [PATCH 10/25] feat: begin registry fetch validation --- grpc/agent/agent_windows.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 74c08257..38dfaf3f 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -5,6 +5,7 @@ package p // package main // uncomment for testing funcs below import ( + "golang.org/x/sys/windows/registry" "crypto/md5" "fmt" "io" @@ -145,6 +146,20 @@ func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) return true, nil } +func GetRegistry(path string) (bool, error) { // exists (boolean) + registry, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) + if err != nil { + return false, err + } + defer registry.Close() + + s, _, err := registry.GetStringValue("SystemRoot") + if err != nil { + return false, err + } + return true, nil +} + func NetHttpContentRegex(full_url string) (string, error) { // content hash (string) net_resp, err := http.Get(full_url) if err != nil { From 911dc7614bce0d830b3145c72fb1f9781e6dd827 Mon Sep 17 00:00:00 2001 From: Colden G <70536917+grietzercs@users.noreply.github.com> Date: Wed, 2 Feb 2022 13:36:25 -0500 Subject: [PATCH 11/25] Added validations.go manually --- ent/schema/validations.go | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 ent/schema/validations.go diff --git a/ent/schema/validations.go b/ent/schema/validations.go new file mode 100644 index 00000000..32b5932b --- /dev/null +++ b/ent/schema/validations.go @@ -0,0 +1,51 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" + "github.com/google/uuid" +) + +// AgentTask holds the schema definition for the AgentTask entity. +type Validator struct { + ent.Schema +} + +// Fields of the AgentTask. +func (Validator) Fields() []ent.Field { + return []ent.Field{ + field.UUID("id", uuid.UUID{}). + Default(uuid.New), + field.Enum("command").Values( + //this should be only execute? + //this section is pending review + "EXECUTE", + ), + field.String("args"), + field.Int("number"), + field.String("output").Default(""), + field.Enum("state").Values("AWAITING", "INPROGRESS", "FAILED", "COMPLETE"), + field.String("error_message").Default(""), + } +} + +// Edges of the AgentTask. +func (Validator) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("Script", ProvisioningStep.Type). + StructTag(`hcl:"`), + edge.To("Command", ProvisionedHost.Type). + Unique(), + edge.To("DNSRecord", ProvisioningStep.Type). + Unique(), + edge.To("FileDelete", ProvisioningStep.Type). + Unique(), + edge.To("FileDownload", ProvisioningStep.Type). + Unique(), + edge.To("FileExtract", ProvisioningStep.Type). + Unique(), + edge.From("Environment", ProvisioningStep.Type). + Unique(), + } +} From d9f27de43d89420495b139783a0322c6d32974de Mon Sep 17 00:00:00 2001 From: Colden G <70536917+grietzercs@users.noreply.github.com> Date: Wed, 2 Feb 2022 13:37:07 -0500 Subject: [PATCH 12/25] Replaced parser.go via file upload --- loader/parser.go | 2999 +++++++++++++++++++++++----------------------- 1 file changed, 1502 insertions(+), 1497 deletions(-) diff --git a/loader/parser.go b/loader/parser.go index 066fa6ce..17817c51 100755 --- a/loader/parser.go +++ b/loader/parser.go @@ -1,1497 +1,1502 @@ -package loader - -import ( - "context" - "fmt" - "os" - "path" - "path/filepath" - "strings" - - "github.com/gen0cide/laforge/ent" - "github.com/gen0cide/laforge/ent/command" - "github.com/gen0cide/laforge/ent/competition" - "github.com/gen0cide/laforge/ent/disk" - "github.com/gen0cide/laforge/ent/dns" - "github.com/gen0cide/laforge/ent/dnsrecord" - "github.com/gen0cide/laforge/ent/environment" - "github.com/gen0cide/laforge/ent/filedelete" - "github.com/gen0cide/laforge/ent/filedownload" - "github.com/gen0cide/laforge/ent/fileextract" - "github.com/gen0cide/laforge/ent/finding" - "github.com/gen0cide/laforge/ent/host" - "github.com/gen0cide/laforge/ent/hostdependency" - "github.com/gen0cide/laforge/ent/identity" - "github.com/gen0cide/laforge/ent/includednetwork" - "github.com/gen0cide/laforge/ent/network" - "github.com/gen0cide/laforge/ent/script" - "github.com/gen0cide/laforge/loader/include" - "github.com/gen0cide/laforge/logging" - hcl2 "github.com/hashicorp/hcl/v2" - "github.com/hashicorp/hcl/v2/ext/transform" - gohcl2 "github.com/hashicorp/hcl/v2/gohcl" - hcl2parse "github.com/hashicorp/hcl/v2/hclparse" - _ "github.com/mattn/go-sqlite3" - zglob "github.com/mattn/go-zglob" - "github.com/sirupsen/logrus" -) - -// Include defines a named include type -type Include struct { - Path string `hcl:"path,attr"` -} - -type fileGlobResolver struct { - BaseDir string - Parser *hcl2parse.Parser -} - -// DefinedConfigs is the stuct to hold in all the loading for hcl -type DefinedConfigs struct { - Filename string - BaseDir string `hcl:"base_dir,optional" json:"base_dir,omitempty"` - IncludePaths []*Include `hcl:"include,block" json:"include_paths,omitempty"` - DefinedCompetitions []*ent.Competition `hcl:"competition,block" json:"competitions,omitempty"` - DefinedHosts []*ent.Host `hcl:"host,block" json:"hosts,omitempty"` - DefinedNetworks []*ent.Network `hcl:"network,block" json:"networks,omitempty"` - DefinedScripts []*ent.Script `hcl:"script,block" json:"scripts,omitempty"` - DefinedCommands []*ent.Command `hcl:"command,block" json:"defined_commands,omitempty"` - DefinedDNSRecords []*ent.DNSRecord `hcl:"dns_record,block" json:"defined_dns_records,omitempty"` - DefinedEnvironments []*ent.Environment `hcl:"environment,block" json:"environments,omitempty"` - DefinedFileDownload []*ent.FileDownload `hcl:"file_download,block" json:"file_download,omitempty"` - DefinedFileDelete []*ent.FileDelete `hcl:"file_delete,block" json:"file_delete,omitempty"` - DefinedFileExtract []*ent.FileExtract `hcl:"file_extract,block" json:"file_extract,omitempty"` - DefinedIdentities []*ent.Identity `hcl:"identity,block" json:"identities,omitempty"` - Competitions map[string]*ent.Competition `json:"-"` - Hosts map[string]*ent.Host `json:"-"` - Networks map[string]*ent.Network `json:"-"` - Scripts map[string]*ent.Script `json:"-"` - Commands map[string]*ent.Command `json:"-"` - DNSRecords map[string]*ent.DNSRecord `json:"-"` - Environments map[string]*ent.Environment `json:"-"` - FileDownload map[string]*ent.FileDownload `json:"-"` - FileDelete map[string]*ent.FileDelete `json:"-"` - FileExtract map[string]*ent.FileExtract `json:"-"` - Identities map[string]*ent.Identity `json:"-"` -} - -// Loader defines the Laforge configuration loader object -type Loader struct { - // Parser is the actual HCLv2 parser - Parser *hcl2parse.Parser - - // SourceFile is the location of the first file loaded - SourceFile string - - // ConfigMap contains all the configuration steps - ConfigMap map[string]*DefinedConfigs -} - -// FileGlobResolver is a modified FileResolver in the HCLv2 include extension that accounts for globbed -// includes: -// include { -// path = "./foo/*.laforge" -// } -func FileGlobResolver(baseDir string, parser *hcl2parse.Parser) include.Resolver { - return &fileGlobResolver{ - BaseDir: baseDir, - Parser: parser, - } -} - -func (r fileGlobResolver) ResolveBodyPath(path string, refRange hcl2.Range) (hcl2.Body, hcl2.Diagnostics) { - callerFile := filepath.Join(refRange.Filename) - callerDir := filepath.Dir(callerFile) - targetFile := filepath.Join(callerDir, path) - body := hcl2.EmptyBody() - var diags hcl2.Diagnostics - if strings.Contains(targetFile, `*`) { - matches, err := zglob.Glob(targetFile) - if err != nil { - return body, hcl2.Diagnostics{&hcl2.Diagnostic{ - Severity: hcl2.DiagError, - Summary: "directory glob error", - Detail: fmt.Sprintf("could not glob on %s: %v", targetFile, err), - }} - } - for _, m := range matches { - switch { - case strings.HasSuffix(m, ".json"): - _, newDiags := r.Parser.ParseJSONFile(m) - diags = diags.Extend(newDiags) - case strings.HasSuffix(m, ".laforge"): - _, newDiags := r.Parser.ParseHCLFile(m) - diags = diags.Extend(newDiags) - default: - newDiag := &hcl2.Diagnostic{ - Severity: hcl2.DiagWarning, - Summary: "invalid file in glob", - Detail: fmt.Sprintf("%s is not a valid JSON or Laforge file (glob=%s)", m, targetFile), - } - diags = diags.Append(newDiag) - } - } - } else { - if strings.HasSuffix(targetFile, ".json") { - _, diags = r.Parser.ParseJSONFile(targetFile) - } else { - _, diags = r.Parser.ParseHCLFile(targetFile) - } - if diags.HasErrors() { - for _, e := range diags.Errs() { - ne, ok := e.(*hcl2.Diagnostic) - if ok { - logrus.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) - } - } - } - return nil, diags - } - if diags.HasErrors() { - for _, e := range diags.Errs() { - ne, ok := e.(*hcl2.Diagnostic) - if ok { - logrus.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) - } - } - } - return body, diags -} - -// ParseConfigFile loads a root file into Loader -func (l *Loader) ParseConfigFile(log *logging.Logger, filename string) error { - var diags hcl2.Diagnostics - if strings.HasSuffix(filename, ".json") { - _, diags = l.Parser.ParseJSONFile(filename) - } else { - _, diags = l.Parser.ParseHCLFile(filename) - } - if diags.HasErrors() { - for _, e := range diags.Errs() { - ne, ok := e.(*hcl2.Diagnostic) - if ok { - log.Log.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) - } - } - return diags - } - l.SourceFile = filename - return nil -} - -// Bind enumerates the Loader's original file, performing recursive include loads to the -// Loader, generating ASTs for each dependency. Bind finishes with a call to Deconflict(). -func (l *Loader) Bind(log *logging.Logger) (*DefinedConfigs, error) { - cwd, err := os.Getwd() - if err != nil { - return nil, err - } - root, err := filepath.Abs(cwd) - if err != nil { - return nil, err - } - transformer := include.Transformer("include", nil, FileGlobResolver(root, l.Parser)) - filenames := []string{} - for name := range l.Parser.Files() { - filenames = append([]string{name}, filenames...) - } - currLen := len(l.Parser.Files()) - for { - for name, f := range l.Parser.Files() { - transform.Deep(f.Body, transformer) - exists := false - for _, i := range filenames { - if i == name { - exists = true - } - } - if !exists { - filenames = append([]string{name}, filenames...) - } - newLF := &DefinedConfigs{} - diags := gohcl2.DecodeBody(f.Body, nil, newLF) - if diags.HasErrors() { - for _, e := range diags.Errs() { - ne, ok := e.(*hcl2.Diagnostic) - if ok { - log.Log.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) - } - } - return nil, diags - } - newLF.Filename = name - l.ConfigMap[name] = newLF - } - newLen := len(l.Parser.Files()) - if currLen == newLen { - break - } - currLen = newLen - } - return l.merger(filenames) -} - -// NewLoader returns a default Loader type -func NewLoader() *Loader { - return &Loader{ - Parser: hcl2parse.NewParser(), - ConfigMap: map[string]*DefinedConfigs{}, - SourceFile: "", - } -} - -func (l *Loader) merger(filenames []string) (*DefinedConfigs, error) { - combinedConfigs := &DefinedConfigs{ - Filename: l.SourceFile, - Competitions: map[string]*ent.Competition{}, - Hosts: map[string]*ent.Host{}, - Networks: map[string]*ent.Network{}, - Scripts: map[string]*ent.Script{}, - Commands: map[string]*ent.Command{}, - DNSRecords: map[string]*ent.DNSRecord{}, - Environments: map[string]*ent.Environment{}, - FileDownload: map[string]*ent.FileDownload{}, - FileDelete: map[string]*ent.FileDelete{}, - FileExtract: map[string]*ent.FileExtract{}, - Identities: map[string]*ent.Identity{}, - } - for _, filename := range filenames { - element := l.ConfigMap[filename] - for _, x := range element.DefinedCompetitions { - obj, found := combinedConfigs.Competitions[x.HclID] - if !found { - combinedConfigs.Competitions[x.HclID] = x - continue - } - if x.RootPassword != "" { - obj.RootPassword = x.RootPassword - } - if x.Config != nil { - obj.Config = x.Config - } - if x.Tags != nil { - obj.Tags = x.Tags - } - if x.HCLCompetitionToDNS != nil { - obj.HCLCompetitionToDNS = x.HCLCompetitionToDNS - } - combinedConfigs.Competitions[x.HclID] = obj - } - for _, x := range element.DefinedHosts { - _, found := combinedConfigs.Hosts[x.HclID] - if !found { - combinedConfigs.Hosts[x.HclID] = x - continue - } - } - for _, x := range element.DefinedNetworks { - _, found := combinedConfigs.Networks[x.HclID] - if !found { - combinedConfigs.Networks[x.HclID] = x - continue - } - } - for _, x := range element.DefinedScripts { - if x.SourceType == "local" { - dir := path.Dir(element.Filename) - absPath := path.Join(dir, x.Source) - x.AbsPath = absPath - } - _, found := combinedConfigs.Scripts[x.HclID] - if !found { - combinedConfigs.Scripts[x.HclID] = x - continue - } - } - for _, x := range element.DefinedCommands { - _, found := combinedConfigs.Commands[x.HclID] - if !found { - combinedConfigs.Commands[x.HclID] = x - continue - } - } - for _, x := range element.DefinedDNSRecords { - _, found := combinedConfigs.DNSRecords[x.HclID] - if !found { - combinedConfigs.DNSRecords[x.HclID] = x - continue - } - } - for _, x := range element.DefinedEnvironments { - _, found := combinedConfigs.Environments[x.HclID] - if !found { - combinedConfigs.Environments[x.HclID] = x - continue - } - } - for _, x := range element.DefinedFileDownload { - _, found := combinedConfigs.FileDownload[x.HclID] - dir := path.Dir(element.Filename) - absPath := path.Join(dir, x.Source) - x.AbsPath = absPath - if !found { - combinedConfigs.FileDownload[x.HclID] = x - continue - } - } - for _, x := range element.DefinedFileDelete { - element.FileDelete[x.HclID] = x - } - for _, x := range element.DefinedFileExtract { - element.FileExtract[x.HclID] = x - } - for _, x := range element.DefinedIdentities { - _, found := combinedConfigs.Identities[x.HclID] - if !found { - combinedConfigs.Identities[x.HclID] = x - continue - } - } - } - return combinedConfigs, nil -} - -// LoadEnvironment Loads in enviroment at specified filepath -func LoadEnvironment(ctx context.Context, client *ent.Client, log *logging.Logger, filePath string) ([]*ent.Environment, error) { - tloader := NewLoader() - tloader.ParseConfigFile(log, filePath) - loadedConfig, err := tloader.Bind(log) - if err != nil { - log.Log.Errorf("Unable to Load ENV Config: %v Err: %v", filePath, err) - return nil, err - } - log.Log.Infof("Loading environment from: %s", filePath) - return createEnviroments(ctx, client, log, loadedConfig.Environments, loadedConfig) -} - -// Need to combine everything here -func createEnviroments(ctx context.Context, client *ent.Client, log *logging.Logger, configEnvs map[string]*ent.Environment, loadedConfig *DefinedConfigs) ([]*ent.Environment, error) { - returnedEnvironment := []*ent.Environment{} - for _, cEnviroment := range configEnvs { - environmentHosts := []string{} - for _, cIncludedNetwork := range cEnviroment.HCLEnvironmentToIncludedNetwork { - environmentHosts = append(environmentHosts, cIncludedNetwork.Hosts...) - } - returnedCompetitions, returnedDNS, err := createCompetitions(ctx, client, log, loadedConfig.Competitions, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedScripts, returnedFindings, err := createScripts(ctx, client, log, loadedConfig.Scripts, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedCommands, err := createCommands(ctx, client, log, loadedConfig.Commands, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedDNSRecords, err := createDNSRecords(ctx, client, log, loadedConfig.DNSRecords, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedFileDownloads, err := createFileDownload(ctx, client, log, loadedConfig.FileDownload, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedFileDeletes, err := createFileDelete(ctx, client, log, loadedConfig.FileDelete, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedFileExtracts, err := createFileExtract(ctx, client, log, loadedConfig.FileExtract, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedIdentities, err := createIdentities(ctx, client, log, loadedConfig.Identities, cEnviroment.HclID) - if err != nil { - return nil, err - } - returnedNetworks, err := createNetworks(ctx, client, log, loadedConfig.Networks, cEnviroment.HCLEnvironmentToIncludedNetwork, cEnviroment.HclID) - if err != nil { - return nil, err - } - // returnedHostDependencies is empty if ran once but ok when ran multiple times - returnedHosts, returnedHostDependencies, err := createHosts(ctx, client, log, loadedConfig.Hosts, cEnviroment.HclID, environmentHosts) - if err != nil { - return nil, err - } - returnedIncludedNetworks, err := createIncludedNetwork(ctx, client, log, cEnviroment.HCLEnvironmentToIncludedNetwork, cEnviroment.HclID) - if err != nil { - return nil, err - } - entEnvironment, err := client.Environment. - Query(). - Where(environment.HclIDEQ(cEnviroment.HclID)). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - newEnvironment, err := client.Environment.Create(). - SetHclID(cEnviroment.HclID). - SetAdminCidrs(cEnviroment.AdminCidrs). - SetBuilder(cEnviroment.Builder). - SetCompetitionID(cEnviroment.CompetitionID). - SetConfig(cEnviroment.Config). - SetDescription(cEnviroment.Description). - SetExposedVdiPorts(cEnviroment.ExposedVdiPorts). - SetName(cEnviroment.Name). - SetRevision(cEnviroment.Revision). - SetTags(cEnviroment.Tags). - SetTeamCount(cEnviroment.TeamCount). - AddEnvironmentToCompetition(returnedCompetitions...). - AddEnvironmentToScript(returnedScripts...). - AddEnvironmentToFinding(returnedFindings...). - AddEnvironmentToCommand(returnedCommands...). - AddEnvironmentToDNSRecord(returnedDNSRecords...). - AddEnvironmentToFileDownload(returnedFileDownloads...). - AddEnvironmentToFileDelete(returnedFileDeletes...). - AddEnvironmentToFileExtract(returnedFileExtracts...). - AddEnvironmentToIdentity(returnedIdentities...). - AddEnvironmentToNetwork(returnedNetworks...). - AddEnvironmentToHost(returnedHosts...). - AddEnvironmentToHostDependency(returnedHostDependencies...). - AddEnvironmentToIncludedNetwork(returnedIncludedNetworks...). - AddEnvironmentToDNS(returnedDNS...). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Create Environment %v. Err: %v", cEnviroment.HclID, err) - return nil, err - } - _, err = validateHostDependencies(ctx, client, log, returnedHostDependencies, cEnviroment.HclID) - if err != nil { - log.Log.Errorf("Failed to Validate Host Dependencies in Environment %v. Err: %v", cEnviroment.HclID, err) - return nil, err - } - returnedEnvironment = append(returnedEnvironment, newEnvironment) - continue - } - } - entEnvironment, err = entEnvironment.Update(). - SetHclID(cEnviroment.HclID). - SetAdminCidrs(cEnviroment.AdminCidrs). - SetBuilder(cEnviroment.Builder). - SetCompetitionID(cEnviroment.CompetitionID). - SetConfig(cEnviroment.Config). - SetDescription(cEnviroment.Description). - SetExposedVdiPorts(cEnviroment.ExposedVdiPorts). - SetName(cEnviroment.Name). - SetRevision(entEnvironment.Revision + 1). - SetTags(cEnviroment.Tags). - SetTeamCount(cEnviroment.TeamCount). - ClearEnvironmentToCompetition(). - ClearEnvironmentToScript(). - ClearEnvironmentToFinding(). - ClearEnvironmentToCommand(). - ClearEnvironmentToDNSRecord(). - ClearEnvironmentToFileDownload(). - ClearEnvironmentToFileDelete(). - ClearEnvironmentToFileExtract(). - ClearEnvironmentToIdentity(). - ClearEnvironmentToNetwork(). - ClearEnvironmentToHostDependency(). - ClearEnvironmentToIncludedNetwork(). - ClearEnvironmentToDNS(). - ClearEnvironmentToHost(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Environment %v. Err: %v", cEnviroment.HclID, err) - return nil, err - } - entEnvironment, err = entEnvironment.Update(). - AddEnvironmentToCompetition(returnedCompetitions...). - AddEnvironmentToScript(returnedScripts...). - AddEnvironmentToFinding(returnedFindings...). - AddEnvironmentToCommand(returnedCommands...). - AddEnvironmentToDNSRecord(returnedDNSRecords...). - AddEnvironmentToFileDownload(returnedFileDownloads...). - AddEnvironmentToFileDelete(returnedFileDeletes...). - AddEnvironmentToFileExtract(returnedFileExtracts...). - AddEnvironmentToIdentity(returnedIdentities...). - AddEnvironmentToNetwork(returnedNetworks...). - AddEnvironmentToHost(returnedHosts...). - AddEnvironmentToHostDependency(returnedHostDependencies...). - AddEnvironmentToIncludedNetwork(returnedIncludedNetworks...). - AddEnvironmentToDNS(returnedDNS...). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Environment %v with it's edges. Err: %v", cEnviroment.HclID, err) - return nil, err - } - _, err = validateHostDependencies(ctx, client, log, returnedHostDependencies, cEnviroment.HclID) - if err != nil { - log.Log.Errorf("Failed to Validate Host Dependencies in Environment %v. Err: %v", cEnviroment.HclID, err) - return nil, err - } - returnedEnvironment = append(returnedEnvironment, entEnvironment) - } - return returnedEnvironment, nil -} - -func createCompetitions(ctx context.Context, client *ent.Client, log *logging.Logger, configCompetitions map[string]*ent.Competition, envHclID string) ([]*ent.Competition, []*ent.DNS, error) { - bulk := []*ent.CompetitionCreate{} - returnedCompetitions := []*ent.Competition{} - returnedAllDNS := []*ent.DNS{} - for _, cCompetition := range configCompetitions { - returnedDNS, err := createDNS(ctx, client, log, cCompetition.HCLCompetitionToDNS, envHclID) - if err != nil { - return nil, nil, err - } - entCompetition, err := client.Competition. - Query(). - Where( - competition.And( - competition.HclIDEQ(cCompetition.HclID), - competition.HasCompetitionToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Competition.Create(). - SetConfig(cCompetition.Config). - SetHclID(cCompetition.HclID). - SetRootPassword(cCompetition.RootPassword). - SetTags(cCompetition.Tags). - AddCompetitionToDNS(returnedDNS...) - bulk = append(bulk, createdQuery) - continue - } - } - entCompetition, err = entCompetition.Update(). - SetConfig(cCompetition.Config). - SetHclID(cCompetition.HclID). - SetRootPassword(cCompetition.RootPassword). - SetTags(cCompetition.Tags). - ClearCompetitionToDNS(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Competition %v. Err: %v", cCompetition.HclID, err) - return nil, nil, err - } - _, err = entCompetition.Update().AddCompetitionToDNS(returnedDNS...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Competition %v with DNS. Err: %v", cCompetition.HclID, err) - return nil, nil, err - } - returnedAllDNS = append(returnedAllDNS, returnedDNS...) - returnedCompetitions = append(returnedCompetitions, entCompetition) - } - if len(bulk) > 0 { - dbCompetitions, err := client.Competition.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Competitions. Err: %v", err) - return nil, nil, err - } - returnedCompetitions = append(returnedCompetitions, dbCompetitions...) - } - return returnedCompetitions, returnedAllDNS, nil -} - -func removeDuplicateValues(stringSlice []string) []string { - keys := make(map[string]bool) - list := []string{} - - // If the key(values of the slice) is not equal - // to the already present value in new slice (list) - // then we append it. else we jump on another element. - for _, entry := range stringSlice { - if _, value := keys[entry]; !value { - keys[entry] = true - list = append(list, entry) - } - } - return list -} - -func createHosts(ctx context.Context, client *ent.Client, log *logging.Logger, configHosts map[string]*ent.Host, envHclID string, environmentHosts []string) ([]*ent.Host, []*ent.HostDependency, error) { - returnedHosts := []*ent.Host{} - returnedAllHostDependencies := []*ent.HostDependency{} - environmentHosts = removeDuplicateValues(environmentHosts) - for _, cHostID := range environmentHosts { - cHost, ok := configHosts[cHostID] - if !ok { - log.Log.Errorf("Host %v was not defined in the Enviroment %v", cHostID, envHclID) - return nil, nil, fmt.Errorf("err: Host %v was not defined in the Enviroment %v", cHostID, envHclID) - } - returnedDisk, err := createDisk(ctx, client, log, cHost.HCLHostToDisk, cHost.HclID, envHclID) - if err != nil { - return nil, nil, err - } - entHost, err := client.Host. - Query(). - Where( - host.And( - host.HclIDEQ(cHost.HclID), - host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - entHost, err = client.Host.Create(). - SetAllowMACChanges(cHost.AllowMACChanges). - SetDescription(cHost.Description). - SetExposedTCPPorts(cHost.ExposedTCPPorts). - SetExposedUDPPorts(cHost.ExposedUDPPorts). - SetHclID(cHost.HclID). - SetHostname(cHost.Hostname). - SetInstanceSize(cHost.InstanceSize). - SetLastOctet(cHost.LastOctet). - SetOS(cHost.OS). - SetOverridePassword(cHost.OverridePassword). - SetProvisionSteps(cHost.ProvisionSteps). - SetTags(cHost.Tags). - SetUserGroups(cHost.UserGroups). - SetVars(cHost.Vars). - SetHostToDisk(returnedDisk). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Create Host %v. Err: %v", cHost.HclID, err) - return nil, nil, err - } - } else { - return nil, nil, err - } - } else { - entHost, err = entHost.Update(). - SetAllowMACChanges(cHost.AllowMACChanges). - SetDescription(cHost.Description). - SetExposedTCPPorts(cHost.ExposedTCPPorts). - SetExposedUDPPorts(cHost.ExposedUDPPorts). - SetHclID(cHost.HclID). - SetHostname(cHost.Hostname). - SetInstanceSize(cHost.InstanceSize). - SetLastOctet(cHost.LastOctet). - SetOS(cHost.OS). - SetOverridePassword(cHost.OverridePassword). - SetProvisionSteps(cHost.ProvisionSteps). - SetTags(cHost.Tags). - SetUserGroups(cHost.UserGroups). - SetVars(cHost.Vars). - ClearHostToDisk(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Host %v. Err: %v", cHost.HclID, err) - return nil, nil, err - } - _, err = entHost.Update().SetHostToDisk(returnedDisk).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Disk to Host %v. Err: %v", cHost.HclID, err) - return nil, nil, err - } - } - - returnedHosts = append(returnedHosts, entHost) - returnedHostDependencies, err := createHostDependencies(ctx, client, log, cHost.HCLDependOnHostToHostDependency, envHclID, entHost) - if err != nil { - return nil, nil, err - } - returnedAllHostDependencies = append(returnedAllHostDependencies, returnedHostDependencies...) - } - return returnedHosts, returnedAllHostDependencies, nil -} - -func createNetworks(ctx context.Context, client *ent.Client, log *logging.Logger, configNetworks map[string]*ent.Network, configIncludedNetworks []*ent.IncludedNetwork, envHclID string) ([]*ent.Network, error) { - bulk := []*ent.NetworkCreate{} - returnedNetworks := []*ent.Network{} - for _, cNetwork := range configNetworks { - included := false - for _, cIncludedNetwork := range configIncludedNetworks { - if cIncludedNetwork.Name == cNetwork.HclID { - included = true - break - } - } - if !included { - continue - } - entNetwork, err := client.Network. - Query(). - Where( - network.And( - network.HclIDEQ(cNetwork.HclID), - network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Network.Create(). - SetCidr(cNetwork.Cidr). - SetHclID(cNetwork.HclID). - SetName(cNetwork.Name). - SetTags(cNetwork.Tags). - SetVars(cNetwork.Vars). - SetVdiVisible(cNetwork.VdiVisible) - bulk = append(bulk, createdQuery) - continue - } - } - entNetwork, err = entNetwork.Update(). - SetCidr(cNetwork.Cidr). - SetHclID(cNetwork.HclID). - SetName(cNetwork.Name). - SetTags(cNetwork.Tags). - SetVars(cNetwork.Vars). - SetVdiVisible(cNetwork.VdiVisible). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Network %v. Err: %v", cNetwork.HclID, err) - return nil, err - } - returnedNetworks = append(returnedNetworks, entNetwork) - } - if len(bulk) > 0 { - dbNetwork, err := client.Network.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Networks. Err: %v", err) - return nil, err - } - returnedNetworks = append(returnedNetworks, dbNetwork...) - } - return returnedNetworks, nil -} - -func createScripts(ctx context.Context, client *ent.Client, log *logging.Logger, configScript map[string]*ent.Script, envHclID string) ([]*ent.Script, []*ent.Finding, error) { - bulk := []*ent.ScriptCreate{} - returnedScripts := []*ent.Script{} - returnedAllFindings := []*ent.Finding{} - for _, cScript := range configScript { - returnedFindings, err := createFindings(ctx, client, log, cScript.HCLScriptToFinding, envHclID, cScript.HclID) - if err != nil { - return nil, nil, err - } - entScript, err := client.Script. - Query(). - Where( - script.And( - script.HclIDEQ(cScript.HclID), - script.HasScriptToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Script.Create(). - SetHclID(cScript.HclID). - SetName(cScript.Name). - SetLanguage(cScript.Language). - SetDescription(cScript.Description). - SetSource(cScript.Source). - SetSourceType(cScript.SourceType). - SetCooldown(cScript.Cooldown). - SetTimeout(cScript.Timeout). - SetIgnoreErrors(cScript.IgnoreErrors). - SetArgs(cScript.Args). - SetDisabled(cScript.Disabled). - SetVars(cScript.Vars). - SetTags(cScript.Tags). - SetAbsPath(cScript.AbsPath). - AddScriptToFinding(returnedFindings...) - bulk = append(bulk, createdQuery) - continue - } - } - entScript, err = entScript.Update(). - SetHclID(cScript.HclID). - SetName(cScript.Name). - SetLanguage(cScript.Language). - SetDescription(cScript.Description). - SetSource(cScript.Source). - SetSourceType(cScript.SourceType). - SetCooldown(cScript.Cooldown). - SetTimeout(cScript.Timeout). - SetIgnoreErrors(cScript.IgnoreErrors). - SetArgs(cScript.Args). - SetDisabled(cScript.Disabled). - SetVars(cScript.Vars). - SetTags(cScript.Tags). - SetAbsPath(cScript.AbsPath). - ClearScriptToFinding(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Script %v. Err: %v", cScript.HclID, err) - return nil, nil, err - } - _, err = entScript.Update().AddScriptToFinding(returnedFindings...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Script %v with it's Findings. Err: %v", cScript.HclID, err) - return nil, nil, err - } - returnedAllFindings = append(returnedAllFindings, returnedFindings...) - returnedScripts = append(returnedScripts, entScript) - } - if len(bulk) > 0 { - dbScript, err := client.Script.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Scripts. Err: %v", err) - return nil, nil, err - } - returnedScripts = append(returnedScripts, dbScript...) - } - return returnedScripts, returnedAllFindings, nil -} - -func createCommands(ctx context.Context, client *ent.Client, log *logging.Logger, configCommands map[string]*ent.Command, envHclID string) ([]*ent.Command, error) { - bulk := []*ent.CommandCreate{} - returnedCommands := []*ent.Command{} - for _, cCommand := range configCommands { - entCommand, err := client.Command. - Query(). - Where( - command.And( - command.HclIDEQ(cCommand.HclID), - command.HasCommandToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Command.Create(). - SetArgs(cCommand.Args). - SetCooldown(cCommand.Cooldown). - SetDescription(cCommand.Description). - SetDisabled(cCommand.Disabled). - SetHclID(cCommand.HclID). - SetIgnoreErrors(cCommand.IgnoreErrors). - SetName(cCommand.Name). - SetProgram(cCommand.Program). - SetTags(cCommand.Tags). - SetTimeout(cCommand.Timeout). - SetVars(cCommand.Vars) - bulk = append(bulk, createdQuery) - continue - } - } - entCommand, err = entCommand.Update(). - SetArgs(cCommand.Args). - SetCooldown(cCommand.Cooldown). - SetDescription(cCommand.Description). - SetDisabled(cCommand.Disabled). - SetHclID(cCommand.HclID). - SetIgnoreErrors(cCommand.IgnoreErrors). - SetName(cCommand.Name). - SetProgram(cCommand.Program). - SetTags(cCommand.Tags). - SetTimeout(cCommand.Timeout). - SetVars(cCommand.Vars). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Command %v. Err: %v", cCommand.HclID, err) - return nil, err - } - returnedCommands = append(returnedCommands, entCommand) - } - if len(bulk) > 0 { - dbCommand, err := client.Command.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Command. Err: %v", err) - return nil, err - } - returnedCommands = append(returnedCommands, dbCommand...) - } - return returnedCommands, nil -} - -func createDNSRecords(ctx context.Context, client *ent.Client, log *logging.Logger, configDNSRecords map[string]*ent.DNSRecord, envHclID string) ([]*ent.DNSRecord, error) { - bulk := []*ent.DNSRecordCreate{} - returnedDNSRecords := []*ent.DNSRecord{} - for _, cDNSRecord := range configDNSRecords { - entDNSRecord, err := client.DNSRecord. - Query(). - Where( - dnsrecord.And( - dnsrecord.HclIDEQ(cDNSRecord.HclID), - dnsrecord.HasDNSRecordToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.DNSRecord.Create(). - SetDisabled(cDNSRecord.Disabled). - SetHclID(cDNSRecord.HclID). - SetName(cDNSRecord.Name). - SetTags(cDNSRecord.Tags). - SetType(cDNSRecord.Type). - SetValues(cDNSRecord.Values). - SetVars(cDNSRecord.Vars). - SetZone(cDNSRecord.Zone) - bulk = append(bulk, createdQuery) - continue - } - } - entDNSRecord, err = entDNSRecord.Update(). - SetDisabled(cDNSRecord.Disabled). - SetHclID(cDNSRecord.HclID). - SetName(cDNSRecord.Name). - SetTags(cDNSRecord.Tags). - SetType(cDNSRecord.Type). - SetValues(cDNSRecord.Values). - SetVars(cDNSRecord.Vars). - SetZone(cDNSRecord.Zone). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update DNS Record %v. Err: %v", cDNSRecord.HclID, err) - return nil, err - } - returnedDNSRecords = append(returnedDNSRecords, entDNSRecord) - } - if len(bulk) > 0 { - dbDNSRecords, err := client.DNSRecord.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk DNS Records. Err: %v", err) - return nil, err - } - returnedDNSRecords = append(returnedDNSRecords, dbDNSRecords...) - } - return returnedDNSRecords, nil -} - -func createFileDownload(ctx context.Context, client *ent.Client, log *logging.Logger, configFileDownloads map[string]*ent.FileDownload, envHclID string) ([]*ent.FileDownload, error) { - bulk := []*ent.FileDownloadCreate{} - returnedFileDownloads := []*ent.FileDownload{} - for _, cFileDownload := range configFileDownloads { - entFileDownload, err := client.FileDownload. - Query(). - Where( - filedownload.And( - filedownload.HclIDEQ(cFileDownload.HclID), - filedownload.HasFileDownloadToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.FileDownload.Create(). - SetHclID(cFileDownload.HclID). - SetSourceType(cFileDownload.SourceType). - SetSource(cFileDownload.Source). - SetDestination(cFileDownload.Destination). - SetTemplate(cFileDownload.Template). - SetPerms(cFileDownload.Perms). - SetDisabled(cFileDownload.Disabled). - SetMd5(cFileDownload.Md5). - SetAbsPath(cFileDownload.AbsPath). - SetTags(cFileDownload.Tags) - bulk = append(bulk, createdQuery) - continue - } - } - entFileDownload, err = entFileDownload.Update(). - SetHclID(cFileDownload.HclID). - SetSourceType(cFileDownload.SourceType). - SetSource(cFileDownload.Source). - SetDestination(cFileDownload.Destination). - SetTemplate(cFileDownload.Template). - SetPerms(cFileDownload.Perms). - SetDisabled(cFileDownload.Disabled). - SetMd5(cFileDownload.Md5). - SetAbsPath(cFileDownload.AbsPath). - SetTags(cFileDownload.Tags). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update File Download %v. Err: %v", cFileDownload.HclID, err) - return nil, err - } - returnedFileDownloads = append(returnedFileDownloads, entFileDownload) - } - if len(bulk) > 0 { - dbFileDownloads, err := client.FileDownload.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk File Downloads. Err: %v", err) - return nil, err - } - returnedFileDownloads = append(returnedFileDownloads, dbFileDownloads...) - } - return returnedFileDownloads, nil -} - -func createFileDelete(ctx context.Context, client *ent.Client, log *logging.Logger, configFileDeletes map[string]*ent.FileDelete, envHclID string) ([]*ent.FileDelete, error) { - bulk := []*ent.FileDeleteCreate{} - returnedFileDeletes := []*ent.FileDelete{} - for _, cFileDelete := range configFileDeletes { - entFileDelete, err := client.FileDelete. - Query(). - Where( - filedelete.And( - filedelete.HclIDEQ(cFileDelete.HclID), - filedelete.HasFileDeleteToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.FileDelete.Create(). - SetHclID(cFileDelete.HclID). - SetPath(cFileDelete.Path). - SetTags(cFileDelete.Tags) - bulk = append(bulk, createdQuery) - continue - } - } - entFileDelete, err = entFileDelete.Update(). - SetHclID(cFileDelete.HclID). - SetPath(cFileDelete.Path). - SetTags(cFileDelete.Tags). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update File Delete %v. Err: %v", cFileDelete.HclID, err) - return nil, err - } - returnedFileDeletes = append(returnedFileDeletes, entFileDelete) - } - if len(bulk) > 0 { - dbFileDelete, err := client.FileDelete.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk File Delete. Err: %v", err) - return nil, err - } - returnedFileDeletes = append(returnedFileDeletes, dbFileDelete...) - } - return returnedFileDeletes, nil -} - -func createFileExtract(ctx context.Context, client *ent.Client, log *logging.Logger, configFileExtracts map[string]*ent.FileExtract, envHclID string) ([]*ent.FileExtract, error) { - bulk := []*ent.FileExtractCreate{} - returnedFileExtracts := []*ent.FileExtract{} - for _, cFileExtract := range configFileExtracts { - entFileExtract, err := client.FileExtract. - Query(). - Where( - fileextract.And( - fileextract.HclIDEQ(cFileExtract.HclID), - fileextract.HasFileExtractToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.FileExtract.Create(). - SetDestination(cFileExtract.Destination). - SetHclID(cFileExtract.HclID). - SetSource(cFileExtract.Source). - SetTags(cFileExtract.Tags). - SetType(cFileExtract.Type) - bulk = append(bulk, createdQuery) - continue - } - } - entFileExtract, err = entFileExtract.Update(). - SetDestination(cFileExtract.Destination). - SetHclID(cFileExtract.HclID). - SetSource(cFileExtract.Source). - SetTags(cFileExtract.Tags). - SetType(cFileExtract.Type). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update File Extract %v. Err: %v", cFileExtract.HclID, err) - return nil, err - } - returnedFileExtracts = append(returnedFileExtracts, entFileExtract) - } - if len(bulk) > 0 { - dbFileExtracts, err := client.FileExtract.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk File Extract. Err: %v", err) - return nil, err - } - returnedFileExtracts = append(returnedFileExtracts, dbFileExtracts...) - } - return returnedFileExtracts, nil -} - -func createIdentities(ctx context.Context, client *ent.Client, log *logging.Logger, configIdentities map[string]*ent.Identity, envHclID string) ([]*ent.Identity, error) { - bulk := []*ent.IdentityCreate{} - returnedIdentities := []*ent.Identity{} - for _, cIdentity := range configIdentities { - entIdentity, err := client.Identity. - Query(). - Where( - identity.And( - identity.HclIDEQ(cIdentity.HclID), - identity.HasIdentityToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Identity.Create(). - SetAvatarFile(cIdentity.AvatarFile). - SetDescription(cIdentity.Description). - SetEmail(cIdentity.Email). - SetFirstName(cIdentity.FirstName). - SetHclID(cIdentity.HclID). - SetLastName(cIdentity.LastName). - SetPassword(cIdentity.Password). - SetVars(cIdentity.Vars). - SetTags(cIdentity.Tags) - bulk = append(bulk, createdQuery) - continue - } - } - entIdentity, err = entIdentity.Update(). - SetAvatarFile(cIdentity.AvatarFile). - SetDescription(cIdentity.Description). - SetEmail(cIdentity.Email). - SetFirstName(cIdentity.FirstName). - SetHclID(cIdentity.HclID). - SetLastName(cIdentity.LastName). - SetPassword(cIdentity.Password). - SetVars(cIdentity.Vars). - SetTags(cIdentity.Tags). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Identity %v. Err: %v", cIdentity.HclID, err) - return nil, err - } - returnedIdentities = append(returnedIdentities, entIdentity) - } - if len(bulk) > 0 { - dbIdentities, err := client.Identity.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Identities. Err: %v", err) - return nil, err - } - returnedIdentities = append(returnedIdentities, dbIdentities...) - } - return returnedIdentities, nil -} - -func createFindings(ctx context.Context, client *ent.Client, log *logging.Logger, configFindings []*ent.Finding, envHclID string, entScriptID string) ([]*ent.Finding, error) { - bulk := []*ent.FindingCreate{} - returnedFindings := []*ent.Finding{} - for _, cFinding := range configFindings { - entFinding, err := client.Finding. - Query(). - Where( - finding.And( - finding.Name(cFinding.Name), - finding.HasFindingToEnvironmentWith(environment.HclIDEQ(envHclID)), - finding.HasFindingToScriptWith(script.HclID(entScriptID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.Finding.Create(). - SetDescription(cFinding.Description). - SetDifficulty(cFinding.Difficulty). - SetName(cFinding.Name). - SetSeverity(cFinding.Severity). - SetTags(cFinding.Tags) - bulk = append(bulk, createdQuery) - continue - } - } - entFinding, err = entFinding.Update(). - SetDescription(cFinding.Description). - SetDifficulty(cFinding.Difficulty). - SetName(cFinding.Name). - SetSeverity(cFinding.Severity). - SetTags(cFinding.Tags). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Finding %v for Script %v in Enviroment %v. Err: %v", cFinding.Name, entScriptID, envHclID, err) - return nil, err - } - returnedFindings = append(returnedFindings, entFinding) - } - if len(bulk) > 0 { - dbFinding, err := client.Finding.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Findings. Err: %v", err) - return nil, err - } - returnedFindings = append(returnedFindings, dbFinding...) - } - return returnedFindings, nil -} - -func createHostDependencies(ctx context.Context, client *ent.Client, log *logging.Logger, configHostDependencies []*ent.HostDependency, envHclID string, dependByHost *ent.Host) ([]*ent.HostDependency, error) { - bulk := []*ent.HostDependencyCreate{} - returnedHostDependencies := []*ent.HostDependency{} - for _, cHostDependency := range configHostDependencies { - entHostDependency, err := client.HostDependency. - Query(). - Where( - hostdependency.And( - hostdependency.HasHostDependencyToDependByHostWith(host.HclIDEQ(dependByHost.HclID)), - hostdependency.HostIDEQ(cHostDependency.HostID), - hostdependency.NetworkIDEQ(cHostDependency.NetworkID), - hostdependency.HasHostDependencyToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.HostDependency.Create(). - SetHostID(cHostDependency.HostID). - SetNetworkID(cHostDependency.NetworkID). - SetHostDependencyToDependByHost(dependByHost) - bulk = append(bulk, createdQuery) - continue - } - } - entHostDependency, err = entHostDependency.Update(). - ClearHostDependencyToDependByHost(). - ClearHostDependencyToDependOnHost(). - ClearHostDependencyToNetwork(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Clear Host Dependency by %v on Host %v Err: %v", dependByHost.HclID, cHostDependency.HostID, err) - return nil, err - } - entHostDependency, err = entHostDependency.Update(). - SetHostDependencyToDependByHost(dependByHost). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update Host Dependency by %v on Host %v Err: %v", dependByHost.HclID, cHostDependency.HostID, err) - return nil, err - } - returnedHostDependencies = append(returnedHostDependencies, entHostDependency) - } - if len(bulk) > 0 { - dbHostDependency, err := client.HostDependency.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Host Dependencies. Err: %v", err) - return nil, err - } - returnedHostDependencies = append(returnedHostDependencies, dbHostDependency...) - } - return returnedHostDependencies, nil -} - -func createDNS(ctx context.Context, client *ent.Client, log *logging.Logger, configDNS []*ent.DNS, envHclID string) ([]*ent.DNS, error) { - bulk := []*ent.DNSCreate{} - returnedDNS := []*ent.DNS{} - for _, cDNS := range configDNS { - entDNS, err := client.DNS. - Query(). - Where( - dns.And( - dns.HclIDEQ(cDNS.HclID), - dns.HasDNSToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.DNS.Create(). - SetConfig(cDNS.Config). - SetDNSServers(cDNS.DNSServers). - SetHclID(cDNS.HclID). - SetNtpServers(cDNS.NtpServers). - SetRootDomain(cDNS.RootDomain). - SetType(cDNS.Type) - bulk = append(bulk, createdQuery) - continue - } - } - entDNS, err = entDNS.Update(). - SetConfig(cDNS.Config). - SetDNSServers(cDNS.DNSServers). - SetHclID(cDNS.HclID). - SetNtpServers(cDNS.NtpServers). - SetRootDomain(cDNS.RootDomain). - SetType(cDNS.Type). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to Update DNS %v. Err: %v", cDNS.HclID, err) - return nil, err - } - returnedDNS = append(returnedDNS, entDNS) - } - if len(bulk) > 0 { - dbDNS, err := client.DNS.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk DNS. Err: %v", err) - return nil, err - } - returnedDNS = append(returnedDNS, dbDNS...) - } - return returnedDNS, nil -} - -func createDisk(ctx context.Context, client *ent.Client, log *logging.Logger, configDisk *ent.Disk, hostHclID string, envHclID string) (*ent.Disk, error) { - entDisk, err := client.Disk. - Query(). - Where( - disk.And( - disk.HasDiskToHostWith( - host.And( - host.HclIDEQ(hostHclID), - host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - entDisk, err = client.Disk.Create(). - SetSize(configDisk.Size). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create Disk for Host %v. Err: %v", hostHclID, err) - return nil, err - } - } - } - entDisk, err = entDisk.Update(). - SetSize(configDisk.Size). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to update Disk Size for Host %v. Err: %v", hostHclID, err) - return nil, err - } - return entDisk, nil -} - -func createIncludedNetwork(ctx context.Context, client *ent.Client, log *logging.Logger, configIncludedNetworks []*ent.IncludedNetwork, envHclID string) ([]*ent.IncludedNetwork, error) { - bulk := []*ent.IncludedNetworkCreate{} - returnedIncludedNetworks := []*ent.IncludedNetwork{} - for _, cIncludedNetwork := range configIncludedNetworks { - entNetwork, err := client.Network.Query().Where( - network.And( - network.HclIDEQ(cIncludedNetwork.Name), - network.Or( - network.Not(network.HasNetworkToEnvironment()), - network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ), - ).Only(ctx) - if err != nil { - log.Log.Errorf("Unable to Query %v network in %v enviroment. Err: %v", cIncludedNetwork.Name, envHclID, err) - return nil, err - } - entHosts := []*ent.Host{} - for _, cHostHclID := range cIncludedNetwork.Hosts { - entHost, err := client.Host.Query().Where( - host.And( - host.HclIDEQ(cHostHclID), - host.Or( - host.Not(host.HasHostToEnvironment()), - host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ), - ).Only(ctx) - if err != nil { - log.Log.Errorf("Unable to Query %v host in %v enviroment. Err: %v", cHostHclID, envHclID, err) - return nil, err - } - entHosts = append(entHosts, entHost) - } - entIncludedNetwork, err := client.IncludedNetwork. - Query(). - Where( - includednetwork.And( - includednetwork.HasIncludedNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), - includednetwork.NameEQ(cIncludedNetwork.Name), - ), - ). - Only(ctx) - if err != nil { - if err == err.(*ent.NotFoundError) { - createdQuery := client.IncludedNetwork.Create(). - SetName(cIncludedNetwork.Name). - SetHosts(cIncludedNetwork.Hosts). - SetIncludedNetworkToNetwork(entNetwork). - AddIncludedNetworkToHost(entHosts...) - bulk = append(bulk, createdQuery) - continue - } - } - entIncludedNetwork, err = entIncludedNetwork.Update(). - SetName(cIncludedNetwork.Name). - SetHosts(cIncludedNetwork.Hosts). - ClearIncludedNetworkToHost(). - ClearIncludedNetworkToNetwork(). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to update the Included Network %v with Hosts %v. Err: %v", cIncludedNetwork.Name, cIncludedNetwork.Hosts, err) - return nil, err - } - entIncludedNetwork, err = entIncludedNetwork.Update(). - AddIncludedNetworkToHost(entHosts...). - SetIncludedNetworkToNetwork(entNetwork). - Save(ctx) - if err != nil { - log.Log.Errorf("Failed to update the Included Network %v Edges with Hosts %v. Err: %v", cIncludedNetwork.Name, cIncludedNetwork.Hosts, err) - return nil, err - } - returnedIncludedNetworks = append(returnedIncludedNetworks, entIncludedNetwork) - } - if len(bulk) > 0 { - dbIncludedNetwork, err := client.IncludedNetwork.CreateBulk(bulk...).Save(ctx) - if err != nil { - log.Log.Errorf("Failed to create bulk Included Network. Err: %v", err) - return nil, err - } - returnedIncludedNetworks = append(returnedIncludedNetworks, dbIncludedNetwork...) - } - return returnedIncludedNetworks, nil -} - -func validateHostDependencies(ctx context.Context, client *ent.Client, log *logging.Logger, uncheckedHostDependencies []*ent.HostDependency, envHclID string) ([]*ent.HostDependency, error) { - checkedHostDependencies := []*ent.HostDependency{} - for _, uncheckedHostDependency := range uncheckedHostDependencies { - entNetwork, err := client.Network.Query().Where( - network.And( - network.HclIDEQ(uncheckedHostDependency.NetworkID), - network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), - ), - ).Only(ctx) - if err != nil { - log.Log.Errorf("Unable to Query %v network in %v enviroment. Err: %v", uncheckedHostDependency.NetworkID, envHclID, err) - return nil, err - } - entHost, err := client.Host.Query().Where( - host.And( - host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), - host.HclIDEQ(uncheckedHostDependency.HostID), - ), - ).Only(ctx) - if err != nil { - log.Log.Errorf("Unable to Query %v host in %v enviroment. Err: %v", uncheckedHostDependency.HostID, envHclID, err) - return nil, err - } - _, err = client.IncludedNetwork.Query().Where( - includednetwork.And( - includednetwork.HasIncludedNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), - includednetwork.HasIncludedNetworkToHostWith(host.HclIDEQ(uncheckedHostDependency.HostID)), - includednetwork.HasIncludedNetworkToNetworkWith(network.HclIDEQ(uncheckedHostDependency.NetworkID)), - ), - ).Only(ctx) - if err != nil { - log.Log.Errorf("Unable to Verify %v host in %v network while loading %v enviroment. Err: %v", uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, envHclID, err) - return nil, err - } - uncheckedHostDependency, err := uncheckedHostDependency.Update(). - ClearHostDependencyToDependOnHost(). - ClearHostDependencyToNetwork(). - Save(ctx) - if err != nil { - dependedByHost, queryErr := uncheckedHostDependency.HostDependencyToDependByHost(ctx) - if queryErr != nil { - log.Log.Errorf("Unable to find the host depended by %v Err: %v", uncheckedHostDependency.HostID, queryErr) - return nil, queryErr - } - log.Log.Errorf("Failed to clear the Host dependency of %v which relies on %v host in %v network. Err: %v", dependedByHost.HclID, uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, err) - return nil, err - } - entHostDependency, err := uncheckedHostDependency.Update(). - SetHostDependencyToDependOnHost(entHost). - SetHostDependencyToNetwork(entNetwork). - Save(ctx) - if err != nil { - dependedByHost, queryErr := uncheckedHostDependency.HostDependencyToDependByHost(ctx) - if queryErr != nil { - log.Log.Errorf("Unable to find the host depended by %v Err: %v", uncheckedHostDependency.HostID, queryErr) - return nil, queryErr - } - log.Log.Errorf("Failed to update the Host dependency of %v which relies on %v host in %v network. Err: %v", dependedByHost.HclID, uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, err) - return nil, err - } - checkedHostDependencies = append(checkedHostDependencies, entHostDependency) - - } - return checkedHostDependencies, nil -} +package loader + +import ( + "context" + "fmt" + "os" + "path" + "path/filepath" + "strings" + + "github.com/gen0cide/laforge/ent" + "github.com/gen0cide/laforge/ent/command" + "github.com/gen0cide/laforge/ent/competition" + "github.com/gen0cide/laforge/ent/disk" + "github.com/gen0cide/laforge/ent/dns" + "github.com/gen0cide/laforge/ent/dnsrecord" + "github.com/gen0cide/laforge/ent/environment" + "github.com/gen0cide/laforge/ent/filedelete" + "github.com/gen0cide/laforge/ent/filedownload" + "github.com/gen0cide/laforge/ent/fileextract" + "github.com/gen0cide/laforge/ent/finding" + "github.com/gen0cide/laforge/ent/host" + "github.com/gen0cide/laforge/ent/hostdependency" + "github.com/gen0cide/laforge/ent/identity" + "github.com/gen0cide/laforge/ent/includednetwork" + "github.com/gen0cide/laforge/ent/network" + "github.com/gen0cide/laforge/ent/script" + "github.com/gen0cide/laforge/loader/include" + "github.com/gen0cide/laforge/logging" + hcl2 "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/ext/transform" + gohcl2 "github.com/hashicorp/hcl/v2/gohcl" + hcl2parse "github.com/hashicorp/hcl/v2/hclparse" + _ "github.com/mattn/go-sqlite3" + zglob "github.com/mattn/go-zglob" + "github.com/sirupsen/logrus" +) + +// Include defines a named include type +type Include struct { + Path string `hcl:"path,attr"` +} + +type fileGlobResolver struct { + BaseDir string + Parser *hcl2parse.Parser +} + +// DefinedConfigs is the stuct to hold in all the loading for hcl +type DefinedConfigs struct { + Filename string + BaseDir string `hcl:"base_dir,optional" json:"base_dir,omitempty"` + IncludePaths []*Include `hcl:"include,block" json:"include_paths,omitempty"` + DefinedCompetitions []*ent.Competition `hcl:"competition,block" json:"competitions,omitempty"` + DefinedHosts []*ent.Host `hcl:"host,block" json:"hosts,omitempty"` + DefinedNetworks []*ent.Network `hcl:"network,block" json:"networks,omitempty"` + DefinedScripts []*ent.Script `hcl:"script,block" json:"scripts,omitempty"` + DefinedCommands []*ent.Command `hcl:"command,block" json:"defined_commands,omitempty"` + DefinedDNSRecords []*ent.DNSRecord `hcl:"dns_record,block" json:"defined_dns_records,omitempty"` + DefinedEnvironments []*ent.Environment `hcl:"environment,block" json:"environments,omitempty"` + DefinedFileDownload []*ent.FileDownload `hcl:"file_download,block" json:"file_download,omitempty"` + DefinedFileDelete []*ent.FileDelete `hcl:"file_delete,block" json:"file_delete,omitempty"` + DefinedFileExtract []*ent.FileExtract `hcl:"file_extract,block" json:"file_extract,omitempty"` + DefinedIdentities []*ent.Identity `hcl:"identity,block" json:"identities,omitempty"` + Competitions map[string]*ent.Competition `json:"-"` + Hosts map[string]*ent.Host `json:"-"` + Networks map[string]*ent.Network `json:"-"` + Scripts map[string]*ent.Script `json:"-"` + Commands map[string]*ent.Command `json:"-"` + DNSRecords map[string]*ent.DNSRecord `json:"-"` + Environments map[string]*ent.Environment `json:"-"` + FileDownload map[string]*ent.FileDownload `json:"-"` + FileDelete map[string]*ent.FileDelete `json:"-"` + FileExtract map[string]*ent.FileExtract `json:"-"` + Identities map[string]*ent.Identity `json:"-"` +} + +// Loader defines the Laforge configuration loader object +type Loader struct { + // Parser is the actual HCLv2 parser + Parser *hcl2parse.Parser + + // SourceFile is the location of the first file loaded + SourceFile string + + // ConfigMap contains all the configuration steps + ConfigMap map[string]*DefinedConfigs +} + +// FileGlobResolver is a modified FileResolver in the HCLv2 include extension that accounts for globbed +// includes: +// include { +// path = "./foo/*.laforge" +// } +func FileGlobResolver(baseDir string, parser *hcl2parse.Parser) include.Resolver { + return &fileGlobResolver{ + BaseDir: baseDir, + Parser: parser, + } +} + +func (r fileGlobResolver) ResolveBodyPath(path string, refRange hcl2.Range) (hcl2.Body, hcl2.Diagnostics) { + callerFile := filepath.Join(refRange.Filename) + callerDir := filepath.Dir(callerFile) + targetFile := filepath.Join(callerDir, path) + body := hcl2.EmptyBody() + var diags hcl2.Diagnostics + if strings.Contains(targetFile, `*`) { + matches, err := zglob.Glob(targetFile) + if err != nil { + return body, hcl2.Diagnostics{&hcl2.Diagnostic{ + Severity: hcl2.DiagError, + Summary: "directory glob error", + Detail: fmt.Sprintf("could not glob on %s: %v", targetFile, err), + }} + } + for _, m := range matches { + switch { + case strings.HasSuffix(m, ".json"): + _, newDiags := r.Parser.ParseJSONFile(m) + diags = diags.Extend(newDiags) + case strings.HasSuffix(m, ".laforge"): + _, newDiags := r.Parser.ParseHCLFile(m) + diags = diags.Extend(newDiags) + default: + newDiag := &hcl2.Diagnostic{ + Severity: hcl2.DiagWarning, + Summary: "invalid file in glob", + Detail: fmt.Sprintf("%s is not a valid JSON or Laforge file (glob=%s)", m, targetFile), + } + diags = diags.Append(newDiag) + } + } + } else { + if strings.HasSuffix(targetFile, ".json") { + _, diags = r.Parser.ParseJSONFile(targetFile) + } else { + _, diags = r.Parser.ParseHCLFile(targetFile) + } + if diags.HasErrors() { + for _, e := range diags.Errs() { + ne, ok := e.(*hcl2.Diagnostic) + if ok { + logrus.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) + } + } + } + return nil, diags + } + if diags.HasErrors() { + for _, e := range diags.Errs() { + ne, ok := e.(*hcl2.Diagnostic) + if ok { + logrus.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) + } + } + } + return body, diags +} + +// ParseConfigFile loads a root file into Loader +func (l *Loader) ParseConfigFile(log *logging.Logger, filename string) error { + var diags hcl2.Diagnostics + if strings.HasSuffix(filename, ".json") { + _, diags = l.Parser.ParseJSONFile(filename) + } else { + _, diags = l.Parser.ParseHCLFile(filename) + } + if diags.HasErrors() { + for _, e := range diags.Errs() { + ne, ok := e.(*hcl2.Diagnostic) + if ok { + log.Log.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) + } + } + return diags + } + l.SourceFile = filename + return nil +} + +// Bind enumerates the Loader's original file, performing recursive include loads to the +// Loader, generating ASTs for each dependency. Bind finishes with a call to Deconflict(). +func (l *Loader) Bind(log *logging.Logger) (*DefinedConfigs, error) { + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + root, err := filepath.Abs(cwd) + if err != nil { + return nil, err + } + transformer := include.Transformer("include", nil, FileGlobResolver(root, l.Parser)) + filenames := []string{} + for name := range l.Parser.Files() { + filenames = append([]string{name}, filenames...) + } + currLen := len(l.Parser.Files()) + for { + for name, f := range l.Parser.Files() { + transform.Deep(f.Body, transformer) + exists := false + for _, i := range filenames { + if i == name { + exists = true + } + } + if !exists { + filenames = append([]string{name}, filenames...) + } + newLF := &DefinedConfigs{} + diags := gohcl2.DecodeBody(f.Body, nil, newLF) + if diags.HasErrors() { + for _, e := range diags.Errs() { + ne, ok := e.(*hcl2.Diagnostic) + if ok { + log.Log.Errorf("Laforge failed to parse a config file:\n Location: %v\n Issue: %v\n Detail: %v", ne.Subject, ne.Summary, ne.Detail) + } + } + return nil, diags + } + newLF.Filename = name + l.ConfigMap[name] = newLF + } + newLen := len(l.Parser.Files()) + if currLen == newLen { + break + } + currLen = newLen + } + return l.merger(filenames) +} + +// NewLoader returns a default Loader type +func NewLoader() *Loader { + return &Loader{ + Parser: hcl2parse.NewParser(), + ConfigMap: map[string]*DefinedConfigs{}, + SourceFile: "", + } +} + +func (l *Loader) merger(filenames []string) (*DefinedConfigs, error) { + combinedConfigs := &DefinedConfigs{ + Filename: l.SourceFile, + Competitions: map[string]*ent.Competition{}, + Hosts: map[string]*ent.Host{}, + Networks: map[string]*ent.Network{}, + Scripts: map[string]*ent.Script{}, + Commands: map[string]*ent.Command{}, + DNSRecords: map[string]*ent.DNSRecord{}, + Environments: map[string]*ent.Environment{}, + FileDownload: map[string]*ent.FileDownload{}, + FileDelete: map[string]*ent.FileDelete{}, + FileExtract: map[string]*ent.FileExtract{}, + Identities: map[string]*ent.Identity{}, + } + for _, filename := range filenames { + element := l.ConfigMap[filename] + for _, x := range element.DefinedCompetitions { + obj, found := combinedConfigs.Competitions[x.HclID] + if !found { + combinedConfigs.Competitions[x.HclID] = x + continue + } + if x.RootPassword != "" { + obj.RootPassword = x.RootPassword + } + if x.Config != nil { + obj.Config = x.Config + } + if x.Tags != nil { + obj.Tags = x.Tags + } + if x.HCLCompetitionToDNS != nil { + obj.HCLCompetitionToDNS = x.HCLCompetitionToDNS + } + combinedConfigs.Competitions[x.HclID] = obj + } + for _, x := range element.DefinedHosts { + _, found := combinedConfigs.Hosts[x.HclID] + if !found { + combinedConfigs.Hosts[x.HclID] = x + continue + } + } + for _, x := range element.DefinedNetworks { + _, found := combinedConfigs.Networks[x.HclID] + if !found { + combinedConfigs.Networks[x.HclID] = x + continue + } + } + for _, x := range element.DefinedScripts { + if x.SourceType == "local" { + dir := path.Dir(element.Filename) + absPath := path.Join(dir, x.Source) + x.AbsPath = absPath + } + _, found := combinedConfigs.Scripts[x.HclID] + if !found { + combinedConfigs.Scripts[x.HclID] = x + continue + } + } + for _, x := range element.DefinedCommands { + _, found := combinedConfigs.Commands[x.HclID] + if !found { + combinedConfigs.Commands[x.HclID] = x + continue + } + } + for _, x := range element.DefinedDNSRecords { + _, found := combinedConfigs.DNSRecords[x.HclID] + if !found { + combinedConfigs.DNSRecords[x.HclID] = x + continue + } + } + for _, x := range element.DefinedEnvironments { + _, found := combinedConfigs.Environments[x.HclID] + if !found { + combinedConfigs.Environments[x.HclID] = x + continue + } + } + for _, x := range element.DefinedFileDownload { + _, found := combinedConfigs.FileDownload[x.HclID] + dir := path.Dir(element.Filename) + absPath := path.Join(dir, x.Source) + x.AbsPath = absPath + if !found { + combinedConfigs.FileDownload[x.HclID] = x + continue + } + } + for _, x := range element.DefinedFileDelete { + element.FileDelete[x.HclID] = x + } + for _, x := range element.DefinedFileExtract { + element.FileExtract[x.HclID] = x + } + for _, x := range element.DefinedIdentities { + _, found := combinedConfigs.Identities[x.HclID] + if !found { + combinedConfigs.Identities[x.HclID] = x + continue + } + } + } + return combinedConfigs, nil +} + +// LoadEnvironment Loads in enviroment at specified filepath +func LoadEnvironment(ctx context.Context, client *ent.Client, log *logging.Logger, filePath string) ([]*ent.Environment, error) { + tloader := NewLoader() + tloader.ParseConfigFile(log, filePath) + loadedConfig, err := tloader.Bind(log) + if err != nil { + log.Log.Errorf("Unable to Load ENV Config: %v Err: %v", filePath, err) + return nil, err + } + log.Log.Infof("Loading environment from: %s", filePath) + return createEnviroments(ctx, client, log, loadedConfig.Environments, loadedConfig) +} + +// Need to combine everything here +func createEnviroments(ctx context.Context, client *ent.Client, log *logging.Logger, configEnvs map[string]*ent.Environment, loadedConfig *DefinedConfigs) ([]*ent.Environment, error) { + returnedEnvironment := []*ent.Environment{} + for _, cEnviroment := range configEnvs { + environmentHosts := []string{} + for _, cIncludedNetwork := range cEnviroment.HCLEnvironmentToIncludedNetwork { + environmentHosts = append(environmentHosts, cIncludedNetwork.Hosts...) + } + returnedCompetitions, returnedDNS, err := createCompetitions(ctx, client, log, loadedConfig.Competitions, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedScripts, returnedFindings, err := createScripts(ctx, client, log, loadedConfig.Scripts, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedCommands, err := createCommands(ctx, client, log, loadedConfig.Commands, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedDNSRecords, err := createDNSRecords(ctx, client, log, loadedConfig.DNSRecords, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedFileDownloads, err := createFileDownload(ctx, client, log, loadedConfig.FileDownload, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedFileDeletes, err := createFileDelete(ctx, client, log, loadedConfig.FileDelete, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedFileExtracts, err := createFileExtract(ctx, client, log, loadedConfig.FileExtract, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedIdentities, err := createIdentities(ctx, client, log, loadedConfig.Identities, cEnviroment.HclID) + if err != nil { + return nil, err + } + returnedNetworks, err := createNetworks(ctx, client, log, loadedConfig.Networks, cEnviroment.HCLEnvironmentToIncludedNetwork, cEnviroment.HclID) + if err != nil { + return nil, err + } + // returnedHostDependencies is empty if ran once but ok when ran multiple times + returnedHosts, returnedHostDependencies, err := createHosts(ctx, client, log, loadedConfig.Hosts, cEnviroment.HclID, environmentHosts) + if err != nil { + return nil, err + } + returnedIncludedNetworks, err := createIncludedNetwork(ctx, client, log, cEnviroment.HCLEnvironmentToIncludedNetwork, cEnviroment.HclID) + if err != nil { + return nil, err + } + entEnvironment, err := client.Environment. + Query(). + Where(environment.HclIDEQ(cEnviroment.HclID)). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + newEnvironment, err := client.Environment.Create(). + SetHclID(cEnviroment.HclID). + SetAdminCidrs(cEnviroment.AdminCidrs). + SetBuilder(cEnviroment.Builder). + SetCompetitionID(cEnviroment.CompetitionID). + SetConfig(cEnviroment.Config). + SetDescription(cEnviroment.Description). + SetExposedVdiPorts(cEnviroment.ExposedVdiPorts). + SetName(cEnviroment.Name). + SetRevision(cEnviroment.Revision). + SetTags(cEnviroment.Tags). + SetTeamCount(cEnviroment.TeamCount). + AddEnvironmentToCompetition(returnedCompetitions...). + AddEnvironmentToScript(returnedScripts...). + AddEnvironmentToFinding(returnedFindings...). + AddEnvironmentToCommand(returnedCommands...). + AddEnvironmentToDNSRecord(returnedDNSRecords...). + AddEnvironmentToFileDownload(returnedFileDownloads...). + AddEnvironmentToFileDelete(returnedFileDeletes...). + AddEnvironmentToFileExtract(returnedFileExtracts...). + AddEnvironmentToIdentity(returnedIdentities...). + AddEnvironmentToNetwork(returnedNetworks...). + AddEnvironmentToHost(returnedHosts...). + AddEnvironmentToHostDependency(returnedHostDependencies...). + AddEnvironmentToIncludedNetwork(returnedIncludedNetworks...). + AddEnvironmentToDNS(returnedDNS...). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Create Environment %v. Err: %v", cEnviroment.HclID, err) + return nil, err + } + _, err = validateHostDependencies(ctx, client, log, returnedHostDependencies, cEnviroment.HclID) + if err != nil { + log.Log.Errorf("Failed to Validate Host Dependencies in Environment %v. Err: %v", cEnviroment.HclID, err) + return nil, err + } + returnedEnvironment = append(returnedEnvironment, newEnvironment) + continue + } + } + entEnvironment, err = entEnvironment.Update(). + SetHclID(cEnviroment.HclID). + SetAdminCidrs(cEnviroment.AdminCidrs). + SetBuilder(cEnviroment.Builder). + SetCompetitionID(cEnviroment.CompetitionID). + SetConfig(cEnviroment.Config). + SetDescription(cEnviroment.Description). + SetExposedVdiPorts(cEnviroment.ExposedVdiPorts). + SetName(cEnviroment.Name). + SetRevision(entEnvironment.Revision + 1). + SetTags(cEnviroment.Tags). + SetTeamCount(cEnviroment.TeamCount). + ClearEnvironmentToCompetition(). + ClearEnvironmentToScript(). + ClearEnvironmentToFinding(). + ClearEnvironmentToCommand(). + ClearEnvironmentToDNSRecord(). + ClearEnvironmentToFileDownload(). + ClearEnvironmentToFileDelete(). + ClearEnvironmentToFileExtract(). + ClearEnvironmentToIdentity(). + ClearEnvironmentToNetwork(). + ClearEnvironmentToHostDependency(). + ClearEnvironmentToIncludedNetwork(). + ClearEnvironmentToDNS(). + ClearEnvironmentToHost(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Environment %v. Err: %v", cEnviroment.HclID, err) + return nil, err + } + entEnvironment, err = entEnvironment.Update(). + AddEnvironmentToCompetition(returnedCompetitions...). + AddEnvironmentToScript(returnedScripts...). + AddEnvironmentToFinding(returnedFindings...). + AddEnvironmentToCommand(returnedCommands...). + AddEnvironmentToDNSRecord(returnedDNSRecords...). + AddEnvironmentToFileDownload(returnedFileDownloads...). + AddEnvironmentToFileDelete(returnedFileDeletes...). + AddEnvironmentToFileExtract(returnedFileExtracts...). + AddEnvironmentToIdentity(returnedIdentities...). + AddEnvironmentToNetwork(returnedNetworks...). + AddEnvironmentToHost(returnedHosts...). + AddEnvironmentToHostDependency(returnedHostDependencies...). + AddEnvironmentToIncludedNetwork(returnedIncludedNetworks...). + AddEnvironmentToDNS(returnedDNS...). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Environment %v with it's edges. Err: %v", cEnviroment.HclID, err) + return nil, err + } + _, err = validateHostDependencies(ctx, client, log, returnedHostDependencies, cEnviroment.HclID) + if err != nil { + log.Log.Errorf("Failed to Validate Host Dependencies in Environment %v. Err: %v", cEnviroment.HclID, err) + return nil, err + } + returnedEnvironment = append(returnedEnvironment, entEnvironment) + } + return returnedEnvironment, nil +} + +func createCompetitions(ctx context.Context, client *ent.Client, log *logging.Logger, configCompetitions map[string]*ent.Competition, envHclID string) ([]*ent.Competition, []*ent.DNS, error) { + bulk := []*ent.CompetitionCreate{} + returnedCompetitions := []*ent.Competition{} + returnedAllDNS := []*ent.DNS{} + for _, cCompetition := range configCompetitions { + returnedDNS, err := createDNS(ctx, client, log, cCompetition.HCLCompetitionToDNS, envHclID) + if err != nil { + return nil, nil, err + } + entCompetition, err := client.Competition. + Query(). + Where( + competition.And( + competition.HclIDEQ(cCompetition.HclID), + competition.HasCompetitionToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Competition.Create(). + SetConfig(cCompetition.Config). + SetHclID(cCompetition.HclID). + SetRootPassword(cCompetition.RootPassword). + SetTags(cCompetition.Tags). + AddCompetitionToDNS(returnedDNS...) + bulk = append(bulk, createdQuery) + continue + } + } + entCompetition, err = entCompetition.Update(). + SetConfig(cCompetition.Config). + SetHclID(cCompetition.HclID). + SetRootPassword(cCompetition.RootPassword). + SetTags(cCompetition.Tags). + ClearCompetitionToDNS(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Competition %v. Err: %v", cCompetition.HclID, err) + return nil, nil, err + } + _, err = entCompetition.Update().AddCompetitionToDNS(returnedDNS...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Competition %v with DNS. Err: %v", cCompetition.HclID, err) + return nil, nil, err + } + returnedAllDNS = append(returnedAllDNS, returnedDNS...) + returnedCompetitions = append(returnedCompetitions, entCompetition) + } + if len(bulk) > 0 { + dbCompetitions, err := client.Competition.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Competitions. Err: %v", err) + return nil, nil, err + } + returnedCompetitions = append(returnedCompetitions, dbCompetitions...) + } + return returnedCompetitions, returnedAllDNS, nil +} + +func removeDuplicateValues(stringSlice []string) []string { + keys := make(map[string]bool) + list := []string{} + + // If the key(values of the slice) is not equal + // to the already present value in new slice (list) + // then we append it. else we jump on another element. + for _, entry := range stringSlice { + if _, value := keys[entry]; !value { + keys[entry] = true + list = append(list, entry) + } + } + return list +} + +func createHosts(ctx context.Context, client *ent.Client, log *logging.Logger, configHosts map[string]*ent.Host, envHclID string, environmentHosts []string) ([]*ent.Host, []*ent.HostDependency, error) { + returnedHosts := []*ent.Host{} + returnedAllHostDependencies := []*ent.HostDependency{} + environmentHosts = removeDuplicateValues(environmentHosts) + for _, cHostID := range environmentHosts { + cHost, ok := configHosts[cHostID] + if !ok { + log.Log.Errorf("Host %v was not defined in the Enviroment %v", cHostID, envHclID) + return nil, nil, fmt.Errorf("err: Host %v was not defined in the Enviroment %v", cHostID, envHclID) + } + returnedDisk, err := createDisk(ctx, client, log, cHost.HCLHostToDisk, cHost.HclID, envHclID) + if err != nil { + return nil, nil, err + } + entHost, err := client.Host. + Query(). + Where( + host.And( + host.HclIDEQ(cHost.HclID), + host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + entHost, err = client.Host.Create(). + SetAllowMACChanges(cHost.AllowMACChanges). + SetDescription(cHost.Description). + SetExposedTCPPorts(cHost.ExposedTCPPorts). + SetExposedUDPPorts(cHost.ExposedUDPPorts). + SetHclID(cHost.HclID). + SetHostname(cHost.Hostname). + SetInstanceSize(cHost.InstanceSize). + SetLastOctet(cHost.LastOctet). + SetOS(cHost.OS). + SetOverridePassword(cHost.OverridePassword). + SetProvisionSteps(cHost.ProvisionSteps). + SetTags(cHost.Tags). + SetUserGroups(cHost.UserGroups). + SetVars(cHost.Vars). + SetHostToDisk(returnedDisk). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Create Host %v. Err: %v", cHost.HclID, err) + return nil, nil, err + } + } else { + return nil, nil, err + } + } else { + entHost, err = entHost.Update(). + SetAllowMACChanges(cHost.AllowMACChanges). + SetDescription(cHost.Description). + SetExposedTCPPorts(cHost.ExposedTCPPorts). + SetExposedUDPPorts(cHost.ExposedUDPPorts). + SetHclID(cHost.HclID). + SetHostname(cHost.Hostname). + SetInstanceSize(cHost.InstanceSize). + SetLastOctet(cHost.LastOctet). + SetOS(cHost.OS). + SetOverridePassword(cHost.OverridePassword). + SetProvisionSteps(cHost.ProvisionSteps). + SetTags(cHost.Tags). + SetUserGroups(cHost.UserGroups). + SetVars(cHost.Vars). + ClearHostToDisk(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Host %v. Err: %v", cHost.HclID, err) + return nil, nil, err + } + _, err = entHost.Update().SetHostToDisk(returnedDisk).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Disk to Host %v. Err: %v", cHost.HclID, err) + return nil, nil, err + } + } + + returnedHosts = append(returnedHosts, entHost) + returnedHostDependencies, err := createHostDependencies(ctx, client, log, cHost.HCLDependOnHostToHostDependency, envHclID, entHost) + if err != nil { + return nil, nil, err + } + returnedAllHostDependencies = append(returnedAllHostDependencies, returnedHostDependencies...) + } + return returnedHosts, returnedAllHostDependencies, nil +} + +func createNetworks(ctx context.Context, client *ent.Client, log *logging.Logger, configNetworks map[string]*ent.Network, configIncludedNetworks []*ent.IncludedNetwork, envHclID string) ([]*ent.Network, error) { + bulk := []*ent.NetworkCreate{} + returnedNetworks := []*ent.Network{} + for _, cNetwork := range configNetworks { + included := false + for _, cIncludedNetwork := range configIncludedNetworks { + if cIncludedNetwork.Name == cNetwork.HclID { + included = true + break + } + } + if !included { + continue + } + entNetwork, err := client.Network. + Query(). + Where( + network.And( + network.HclIDEQ(cNetwork.HclID), + network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Network.Create(). + SetCidr(cNetwork.Cidr). + SetHclID(cNetwork.HclID). + SetName(cNetwork.Name). + SetTags(cNetwork.Tags). + SetVars(cNetwork.Vars). + SetVdiVisible(cNetwork.VdiVisible) + bulk = append(bulk, createdQuery) + continue + } + } + entNetwork, err = entNetwork.Update(). + SetCidr(cNetwork.Cidr). + SetHclID(cNetwork.HclID). + SetName(cNetwork.Name). + SetTags(cNetwork.Tags). + SetVars(cNetwork.Vars). + SetVdiVisible(cNetwork.VdiVisible). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Network %v. Err: %v", cNetwork.HclID, err) + return nil, err + } + returnedNetworks = append(returnedNetworks, entNetwork) + } + if len(bulk) > 0 { + dbNetwork, err := client.Network.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Networks. Err: %v", err) + return nil, err + } + returnedNetworks = append(returnedNetworks, dbNetwork...) + } + return returnedNetworks, nil +} + +func createScripts(ctx context.Context, client *ent.Client, log *logging.Logger, configScript map[string]*ent.Script, envHclID string) ([]*ent.Script, []*ent.Finding, error) { + bulk := []*ent.ScriptCreate{} + returnedScripts := []*ent.Script{} + returnedAllFindings := []*ent.Finding{} + for _, cScript := range configScript { + returnedFindings, err := createFindings(ctx, client, log, cScript.HCLScriptToFinding, envHclID, cScript.HclID) + if err != nil { + return nil, nil, err + } + entScript, err := client.Script. + Query(). + Where( + script.And( + script.HclIDEQ(cScript.HclID), + script.HasScriptToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Script.Create(). + SetHclID(cScript.HclID). + SetName(cScript.Name). + SetLanguage(cScript.Language). + SetDescription(cScript.Description). + SetSource(cScript.Source). + SetSourceType(cScript.SourceType). + SetCooldown(cScript.Cooldown). + SetTimeout(cScript.Timeout). + SetIgnoreErrors(cScript.IgnoreErrors). + SetArgs(cScript.Args). + SetDisabled(cScript.Disabled). + SetVars(cScript.Vars). + SetTags(cScript.Tags). + SetAbsPath(cScript.AbsPath). + AddScriptToFinding(returnedFindings...) + bulk = append(bulk, createdQuery) + continue + } + } + entScript, err = entScript.Update(). + SetHclID(cScript.HclID). + SetName(cScript.Name). + SetLanguage(cScript.Language). + SetDescription(cScript.Description). + SetSource(cScript.Source). + SetSourceType(cScript.SourceType). + SetCooldown(cScript.Cooldown). + SetTimeout(cScript.Timeout). + SetIgnoreErrors(cScript.IgnoreErrors). + SetArgs(cScript.Args). + SetDisabled(cScript.Disabled). + SetVars(cScript.Vars). + SetTags(cScript.Tags). + SetAbsPath(cScript.AbsPath). + ClearScriptToFinding(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Script %v. Err: %v", cScript.HclID, err) + return nil, nil, err + } + _, err = entScript.Update().AddScriptToFinding(returnedFindings...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Script %v with it's Findings. Err: %v", cScript.HclID, err) + return nil, nil, err + } + returnedAllFindings = append(returnedAllFindings, returnedFindings...) + returnedScripts = append(returnedScripts, entScript) + } + if len(bulk) > 0 { + dbScript, err := client.Script.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Scripts. Err: %v", err) + return nil, nil, err + } + returnedScripts = append(returnedScripts, dbScript...) + } + return returnedScripts, returnedAllFindings, nil +} + +func createCommands(ctx context.Context, client *ent.Client, log *logging.Logger, configCommands map[string]*ent.Command, envHclID string) ([]*ent.Command, error) { + bulk := []*ent.CommandCreate{} + returnedCommands := []*ent.Command{} + for _, cCommand := range configCommands { + entCommand, err := client.Command. + Query(). + Where( + command.And( + command.HclIDEQ(cCommand.HclID), + command.HasCommandToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Command.Create(). + SetArgs(cCommand.Args). + SetCooldown(cCommand.Cooldown). + SetDescription(cCommand.Description). + SetDisabled(cCommand.Disabled). + SetHclID(cCommand.HclID). + SetIgnoreErrors(cCommand.IgnoreErrors). + SetName(cCommand.Name). + SetProgram(cCommand.Program). + SetTags(cCommand.Tags). + SetTimeout(cCommand.Timeout). + SetVars(cCommand.Vars) + bulk = append(bulk, createdQuery) + continue + } + } + entCommand, err = entCommand.Update(). + SetArgs(cCommand.Args). + SetCooldown(cCommand.Cooldown). + SetDescription(cCommand.Description). + SetDisabled(cCommand.Disabled). + SetHclID(cCommand.HclID). + SetIgnoreErrors(cCommand.IgnoreErrors). + SetName(cCommand.Name). + SetProgram(cCommand.Program). + SetTags(cCommand.Tags). + SetTimeout(cCommand.Timeout). + SetVars(cCommand.Vars). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Command %v. Err: %v", cCommand.HclID, err) + return nil, err + } + returnedCommands = append(returnedCommands, entCommand) + } + if len(bulk) > 0 { + dbCommand, err := client.Command.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Command. Err: %v", err) + return nil, err + } + returnedCommands = append(returnedCommands, dbCommand...) + } + return returnedCommands, nil +} + +func createDNSRecords(ctx context.Context, client *ent.Client, log *logging.Logger, configDNSRecords map[string]*ent.DNSRecord, envHclID string) ([]*ent.DNSRecord, error) { + bulk := []*ent.DNSRecordCreate{} + returnedDNSRecords := []*ent.DNSRecord{} + for _, cDNSRecord := range configDNSRecords { + entDNSRecord, err := client.DNSRecord. + Query(). + Where( + dnsrecord.And( + dnsrecord.HclIDEQ(cDNSRecord.HclID), + dnsrecord.HasDNSRecordToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.DNSRecord.Create(). + SetDisabled(cDNSRecord.Disabled). + SetHclID(cDNSRecord.HclID). + SetName(cDNSRecord.Name). + SetTags(cDNSRecord.Tags). + SetType(cDNSRecord.Type). + SetValues(cDNSRecord.Values). + SetVars(cDNSRecord.Vars). + SetZone(cDNSRecord.Zone) + bulk = append(bulk, createdQuery) + continue + } + } + entDNSRecord, err = entDNSRecord.Update(). + SetDisabled(cDNSRecord.Disabled). + SetHclID(cDNSRecord.HclID). + SetName(cDNSRecord.Name). + SetTags(cDNSRecord.Tags). + SetType(cDNSRecord.Type). + SetValues(cDNSRecord.Values). + SetVars(cDNSRecord.Vars). + SetZone(cDNSRecord.Zone). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update DNS Record %v. Err: %v", cDNSRecord.HclID, err) + return nil, err + } + returnedDNSRecords = append(returnedDNSRecords, entDNSRecord) + } + if len(bulk) > 0 { + dbDNSRecords, err := client.DNSRecord.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk DNS Records. Err: %v", err) + return nil, err + } + returnedDNSRecords = append(returnedDNSRecords, dbDNSRecords...) + } + return returnedDNSRecords, nil +} + +func createFileDownload(ctx context.Context, client *ent.Client, log *logging.Logger, configFileDownloads map[string]*ent.FileDownload, envHclID string) ([]*ent.FileDownload, error) { + bulk := []*ent.FileDownloadCreate{} + returnedFileDownloads := []*ent.FileDownload{} + for _, cFileDownload := range configFileDownloads { + entFileDownload, err := client.FileDownload. + Query(). + Where( + filedownload.And( + filedownload.HclIDEQ(cFileDownload.HclID), + filedownload.HasFileDownloadToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.FileDownload.Create(). + SetHclID(cFileDownload.HclID). + SetSourceType(cFileDownload.SourceType). + SetSource(cFileDownload.Source). + SetDestination(cFileDownload.Destination). + SetTemplate(cFileDownload.Template). + SetPerms(cFileDownload.Perms). + SetDisabled(cFileDownload.Disabled). + SetMd5(cFileDownload.Md5). + SetAbsPath(cFileDownload.AbsPath). + SetTags(cFileDownload.Tags) + bulk = append(bulk, createdQuery) + continue + } + } + entFileDownload, err = entFileDownload.Update(). + SetHclID(cFileDownload.HclID). + SetSourceType(cFileDownload.SourceType). + SetSource(cFileDownload.Source). + SetDestination(cFileDownload.Destination). + SetTemplate(cFileDownload.Template). + SetPerms(cFileDownload.Perms). + SetDisabled(cFileDownload.Disabled). + SetMd5(cFileDownload.Md5). + SetAbsPath(cFileDownload.AbsPath). + SetTags(cFileDownload.Tags). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update File Download %v. Err: %v", cFileDownload.HclID, err) + return nil, err + } + returnedFileDownloads = append(returnedFileDownloads, entFileDownload) + } + if len(bulk) > 0 { + dbFileDownloads, err := client.FileDownload.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk File Downloads. Err: %v", err) + return nil, err + } + returnedFileDownloads = append(returnedFileDownloads, dbFileDownloads...) + } + return returnedFileDownloads, nil +} + +func createFileDelete(ctx context.Context, client *ent.Client, log *logging.Logger, configFileDeletes map[string]*ent.FileDelete, envHclID string) ([]*ent.FileDelete, error) { + bulk := []*ent.FileDeleteCreate{} + returnedFileDeletes := []*ent.FileDelete{} + for _, cFileDelete := range configFileDeletes { + entFileDelete, err := client.FileDelete. + Query(). + Where( + filedelete.And( + filedelete.HclIDEQ(cFileDelete.HclID), + filedelete.HasFileDeleteToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.FileDelete.Create(). + SetHclID(cFileDelete.HclID). + SetPath(cFileDelete.Path). + SetTags(cFileDelete.Tags) + bulk = append(bulk, createdQuery) + continue + } + } + entFileDelete, err = entFileDelete.Update(). + SetHclID(cFileDelete.HclID). + SetPath(cFileDelete.Path). + SetTags(cFileDelete.Tags). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update File Delete %v. Err: %v", cFileDelete.HclID, err) + return nil, err + } + returnedFileDeletes = append(returnedFileDeletes, entFileDelete) + } + if len(bulk) > 0 { + dbFileDelete, err := client.FileDelete.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk File Delete. Err: %v", err) + return nil, err + } + returnedFileDeletes = append(returnedFileDeletes, dbFileDelete...) + } + return returnedFileDeletes, nil +} + +func createFileExtract(ctx context.Context, client *ent.Client, log *logging.Logger, configFileExtracts map[string]*ent.FileExtract, envHclID string) ([]*ent.FileExtract, error) { + bulk := []*ent.FileExtractCreate{} + returnedFileExtracts := []*ent.FileExtract{} + for _, cFileExtract := range configFileExtracts { + entFileExtract, err := client.FileExtract. + Query(). + Where( + fileextract.And( + fileextract.HclIDEQ(cFileExtract.HclID), + fileextract.HasFileExtractToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.FileExtract.Create(). + SetDestination(cFileExtract.Destination). + SetHclID(cFileExtract.HclID). + SetSource(cFileExtract.Source). + SetTags(cFileExtract.Tags). + SetType(cFileExtract.Type) + bulk = append(bulk, createdQuery) + continue + } + } + entFileExtract, err = entFileExtract.Update(). + SetDestination(cFileExtract.Destination). + SetHclID(cFileExtract.HclID). + SetSource(cFileExtract.Source). + SetTags(cFileExtract.Tags). + SetType(cFileExtract.Type). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update File Extract %v. Err: %v", cFileExtract.HclID, err) + return nil, err + } + returnedFileExtracts = append(returnedFileExtracts, entFileExtract) + } + if len(bulk) > 0 { + dbFileExtracts, err := client.FileExtract.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk File Extract. Err: %v", err) + return nil, err + } + returnedFileExtracts = append(returnedFileExtracts, dbFileExtracts...) + } + return returnedFileExtracts, nil +} + +func createIdentities(ctx context.Context, client *ent.Client, log *logging.Logger, configIdentities map[string]*ent.Identity, envHclID string) ([]*ent.Identity, error) { + bulk := []*ent.IdentityCreate{} + returnedIdentities := []*ent.Identity{} + for _, cIdentity := range configIdentities { + entIdentity, err := client.Identity. + Query(). + Where( + identity.And( + identity.HclIDEQ(cIdentity.HclID), + identity.HasIdentityToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Identity.Create(). + SetAvatarFile(cIdentity.AvatarFile). + SetDescription(cIdentity.Description). + SetEmail(cIdentity.Email). + SetFirstName(cIdentity.FirstName). + SetHclID(cIdentity.HclID). + SetLastName(cIdentity.LastName). + SetPassword(cIdentity.Password). + SetVars(cIdentity.Vars). + SetTags(cIdentity.Tags) + bulk = append(bulk, createdQuery) + continue + } + } + entIdentity, err = entIdentity.Update(). + SetAvatarFile(cIdentity.AvatarFile). + SetDescription(cIdentity.Description). + SetEmail(cIdentity.Email). + SetFirstName(cIdentity.FirstName). + SetHclID(cIdentity.HclID). + SetLastName(cIdentity.LastName). + SetPassword(cIdentity.Password). + SetVars(cIdentity.Vars). + SetTags(cIdentity.Tags). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Identity %v. Err: %v", cIdentity.HclID, err) + return nil, err + } + returnedIdentities = append(returnedIdentities, entIdentity) + } + if len(bulk) > 0 { + dbIdentities, err := client.Identity.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Identities. Err: %v", err) + return nil, err + } + returnedIdentities = append(returnedIdentities, dbIdentities...) + } + return returnedIdentities, nil +} + +func createFindings(ctx context.Context, client *ent.Client, log *logging.Logger, configFindings []*ent.Finding, envHclID string, entScriptID string) ([]*ent.Finding, error) { + bulk := []*ent.FindingCreate{} + returnedFindings := []*ent.Finding{} + for _, cFinding := range configFindings { + entFinding, err := client.Finding. + Query(). + Where( + finding.And( + finding.Name(cFinding.Name), + finding.HasFindingToEnvironmentWith(environment.HclIDEQ(envHclID)), + finding.HasFindingToScriptWith(script.HclID(entScriptID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.Finding.Create(). + SetDescription(cFinding.Description). + SetDifficulty(cFinding.Difficulty). + SetName(cFinding.Name). + SetSeverity(cFinding.Severity). + SetTags(cFinding.Tags) + bulk = append(bulk, createdQuery) + continue + } + } + entFinding, err = entFinding.Update(). + SetDescription(cFinding.Description). + SetDifficulty(cFinding.Difficulty). + SetName(cFinding.Name). + SetSeverity(cFinding.Severity). + SetTags(cFinding.Tags). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Finding %v for Script %v in Enviroment %v. Err: %v", cFinding.Name, entScriptID, envHclID, err) + return nil, err + } + returnedFindings = append(returnedFindings, entFinding) + } + if len(bulk) > 0 { + dbFinding, err := client.Finding.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Findings. Err: %v", err) + return nil, err + } + returnedFindings = append(returnedFindings, dbFinding...) + } + return returnedFindings, nil +} + +func createHostDependencies(ctx context.Context, client *ent.Client, log *logging.Logger, configHostDependencies []*ent.HostDependency, envHclID string, dependByHost *ent.Host) ([]*ent.HostDependency, error) { + bulk := []*ent.HostDependencyCreate{} + returnedHostDependencies := []*ent.HostDependency{} + for _, cHostDependency := range configHostDependencies { + entHostDependency, err := client.HostDependency. + Query(). + Where( + hostdependency.And( + hostdependency.HasHostDependencyToDependByHostWith(host.HclIDEQ(dependByHost.HclID)), + hostdependency.HostIDEQ(cHostDependency.HostID), + hostdependency.NetworkIDEQ(cHostDependency.NetworkID), + hostdependency.HasHostDependencyToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.HostDependency.Create(). + SetHostID(cHostDependency.HostID). + SetNetworkID(cHostDependency.NetworkID). + SetHostDependencyToDependByHost(dependByHost) + bulk = append(bulk, createdQuery) + continue + } + } + entHostDependency, err = entHostDependency.Update(). + ClearHostDependencyToDependByHost(). + ClearHostDependencyToDependOnHost(). + ClearHostDependencyToNetwork(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Clear Host Dependency by %v on Host %v Err: %v", dependByHost.HclID, cHostDependency.HostID, err) + return nil, err + } + entHostDependency, err = entHostDependency.Update(). + SetHostDependencyToDependByHost(dependByHost). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update Host Dependency by %v on Host %v Err: %v", dependByHost.HclID, cHostDependency.HostID, err) + return nil, err + } + returnedHostDependencies = append(returnedHostDependencies, entHostDependency) + } + if len(bulk) > 0 { + dbHostDependency, err := client.HostDependency.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Host Dependencies. Err: %v", err) + return nil, err + } + returnedHostDependencies = append(returnedHostDependencies, dbHostDependency...) + } + return returnedHostDependencies, nil +} + +func createDNS(ctx context.Context, client *ent.Client, log *logging.Logger, configDNS []*ent.DNS, envHclID string) ([]*ent.DNS, error) { + bulk := []*ent.DNSCreate{} + returnedDNS := []*ent.DNS{} + for _, cDNS := range configDNS { + entDNS, err := client.DNS. + Query(). + Where( + dns.And( + dns.HclIDEQ(cDNS.HclID), + dns.HasDNSToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.DNS.Create(). + SetConfig(cDNS.Config). + SetDNSServers(cDNS.DNSServers). + SetHclID(cDNS.HclID). + SetNtpServers(cDNS.NtpServers). + SetRootDomain(cDNS.RootDomain). + SetType(cDNS.Type) + bulk = append(bulk, createdQuery) + continue + } + } + entDNS, err = entDNS.Update(). + SetConfig(cDNS.Config). + SetDNSServers(cDNS.DNSServers). + SetHclID(cDNS.HclID). + SetNtpServers(cDNS.NtpServers). + SetRootDomain(cDNS.RootDomain). + SetType(cDNS.Type). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to Update DNS %v. Err: %v", cDNS.HclID, err) + return nil, err + } + returnedDNS = append(returnedDNS, entDNS) + } + if len(bulk) > 0 { + dbDNS, err := client.DNS.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk DNS. Err: %v", err) + return nil, err + } + returnedDNS = append(returnedDNS, dbDNS...) + } + return returnedDNS, nil +} + +func createDisk(ctx context.Context, client *ent.Client, log *logging.Logger, configDisk *ent.Disk, hostHclID string, envHclID string) (*ent.Disk, error) { + entDisk, err := client.Disk. + Query(). + Where( + disk.And( + disk.HasDiskToHostWith( + host.And( + host.HclIDEQ(hostHclID), + host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + entDisk, err = client.Disk.Create(). + SetSize(configDisk.Size). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create Disk for Host %v. Err: %v", hostHclID, err) + return nil, err + } + } + } + entDisk, err = entDisk.Update(). + SetSize(configDisk.Size). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to update Disk Size for Host %v. Err: %v", hostHclID, err) + return nil, err + } + return entDisk, nil +} + +func createIncludedNetwork(ctx context.Context, client *ent.Client, log *logging.Logger, configIncludedNetworks []*ent.IncludedNetwork, envHclID string) ([]*ent.IncludedNetwork, error) { + bulk := []*ent.IncludedNetworkCreate{} + returnedIncludedNetworks := []*ent.IncludedNetwork{} + for _, cIncludedNetwork := range configIncludedNetworks { + entNetwork, err := client.Network.Query().Where( + network.And( + network.HclIDEQ(cIncludedNetwork.Name), + network.Or( + network.Not(network.HasNetworkToEnvironment()), + network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ), + ).Only(ctx) + if err != nil { + log.Log.Errorf("Unable to Query %v network in %v enviroment. Err: %v", cIncludedNetwork.Name, envHclID, err) + return nil, err + } + entHosts := []*ent.Host{} + for _, cHostHclID := range cIncludedNetwork.Hosts { + entHost, err := client.Host.Query().Where( + host.And( + host.HclIDEQ(cHostHclID), + host.Or( + host.Not(host.HasHostToEnvironment()), + host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ), + ).Only(ctx) + if err != nil { + log.Log.Errorf("Unable to Query %v host in %v enviroment. Err: %v", cHostHclID, envHclID, err) + return nil, err + } + entHosts = append(entHosts, entHost) + } + entIncludedNetwork, err := client.IncludedNetwork. + Query(). + Where( + includednetwork.And( + includednetwork.HasIncludedNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), + includednetwork.NameEQ(cIncludedNetwork.Name), + ), + ). + Only(ctx) + if err != nil { + if err == err.(*ent.NotFoundError) { + createdQuery := client.IncludedNetwork.Create(). + SetName(cIncludedNetwork.Name). + SetHosts(cIncludedNetwork.Hosts). + SetIncludedNetworkToNetwork(entNetwork). + AddIncludedNetworkToHost(entHosts...) + bulk = append(bulk, createdQuery) + continue + } + } + entIncludedNetwork, err = entIncludedNetwork.Update(). + SetName(cIncludedNetwork.Name). + SetHosts(cIncludedNetwork.Hosts). + ClearIncludedNetworkToHost(). + ClearIncludedNetworkToNetwork(). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to update the Included Network %v with Hosts %v. Err: %v", cIncludedNetwork.Name, cIncludedNetwork.Hosts, err) + return nil, err + } + entIncludedNetwork, err = entIncludedNetwork.Update(). + AddIncludedNetworkToHost(entHosts...). + SetIncludedNetworkToNetwork(entNetwork). + Save(ctx) + if err != nil { + log.Log.Errorf("Failed to update the Included Network %v Edges with Hosts %v. Err: %v", cIncludedNetwork.Name, cIncludedNetwork.Hosts, err) + return nil, err + } + returnedIncludedNetworks = append(returnedIncludedNetworks, entIncludedNetwork) + } + if len(bulk) > 0 { + dbIncludedNetwork, err := client.IncludedNetwork.CreateBulk(bulk...).Save(ctx) + if err != nil { + log.Log.Errorf("Failed to create bulk Included Network. Err: %v", err) + return nil, err + } + returnedIncludedNetworks = append(returnedIncludedNetworks, dbIncludedNetwork...) + } + return returnedIncludedNetworks, nil +} + +func validateHostDependencies(ctx context.Context, client *ent.Client, log *logging.Logger, uncheckedHostDependencies []*ent.HostDependency, envHclID string) ([]*ent.HostDependency, error) { + checkedHostDependencies := []*ent.HostDependency{} + for _, uncheckedHostDependency := range uncheckedHostDependencies { + entNetwork, err := client.Network.Query().Where( + network.And( + network.HclIDEQ(uncheckedHostDependency.NetworkID), + network.HasNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), + ), + ).Only(ctx) + if err != nil { + log.Log.Errorf("Unable to Query %v network in %v enviroment. Err: %v", uncheckedHostDependency.NetworkID, envHclID, err) + return nil, err + } + entHost, err := client.Host.Query().Where( + host.And( + host.HasHostToEnvironmentWith(environment.HclIDEQ(envHclID)), + host.HclIDEQ(uncheckedHostDependency.HostID), + ), + ).Only(ctx) + if err != nil { + log.Log.Errorf("Unable to Query %v host in %v enviroment. Err: %v", uncheckedHostDependency.HostID, envHclID, err) + return nil, err + } + _, err = client.IncludedNetwork.Query().Where( + includednetwork.And( + includednetwork.HasIncludedNetworkToEnvironmentWith(environment.HclIDEQ(envHclID)), + includednetwork.HasIncludedNetworkToHostWith(host.HclIDEQ(uncheckedHostDependency.HostID)), + includednetwork.HasIncludedNetworkToNetworkWith(network.HclIDEQ(uncheckedHostDependency.NetworkID)), + ), + ).Only(ctx) + if err != nil { + log.Log.Errorf("Unable to Verify %v host in %v network while loading %v enviroment. Err: %v", uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, envHclID, err) + return nil, err + } + uncheckedHostDependency, err := uncheckedHostDependency.Update(). + ClearHostDependencyToDependOnHost(). + ClearHostDependencyToNetwork(). + Save(ctx) + if err != nil { + dependedByHost, queryErr := uncheckedHostDependency.HostDependencyToDependByHost(ctx) + if queryErr != nil { + log.Log.Errorf("Unable to find the host depended by %v Err: %v", uncheckedHostDependency.HostID, queryErr) + return nil, queryErr + } + log.Log.Errorf("Failed to clear the Host dependency of %v which relies on %v host in %v network. Err: %v", dependedByHost.HclID, uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, err) + return nil, err + } + entHostDependency, err := uncheckedHostDependency.Update(). + SetHostDependencyToDependOnHost(entHost). + SetHostDependencyToNetwork(entNetwork). + Save(ctx) + if err != nil { + dependedByHost, queryErr := uncheckedHostDependency.HostDependencyToDependByHost(ctx) + if queryErr != nil { + log.Log.Errorf("Unable to find the host depended by %v Err: %v", uncheckedHostDependency.HostID, queryErr) + return nil, queryErr + } + log.Log.Errorf("Failed to update the Host dependency of %v which relies on %v host in %v network. Err: %v", dependedByHost.HclID, uncheckedHostDependency.HostID, uncheckedHostDependency.NetworkID, err) + return nil, err + } + checkedHostDependencies = append(checkedHostDependencies, entHostDependency) + + } + return checkedHostDependencies, nil +} + +func validator(ctx context.Context, client *ent.Client, log *logging.Logger, uncheckedHostDependencies []*ent.HostDependency, envHclID string) ([]*ent.HostDependency, error) { + + +} \ No newline at end of file From 00fe7b166c30d8063920c578435a3f1e75427172 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 2 Feb 2022 15:03:07 -0500 Subject: [PATCH 13/25] feat: create validation package, provisionstep build hook Co-authored-by: dileonk Co-authored-by: Colden G. --- ent/schema/agenttask.go | 1 + ent/schema/provisioningstep.go | 1 + ent/schema/validations.go | 16 ++++++++ grpc/agent/agent.go | 1 + grpc/agent/agent_unix.go | 48 +++++++++++++++++----- grpc/agent/agent_windows.go | 6 +-- grpc/proto/agent_proto.pb.go | 74 ++++++++++++++++++---------------- grpc/server/server.go | 7 +++- loader/parser.go | 21 +++++----- planner/build.go | 18 +++++++++ validation/needs_name.go | 8 ++++ 11 files changed, 143 insertions(+), 58 deletions(-) create mode 100644 validation/needs_name.go diff --git a/ent/schema/agenttask.go b/ent/schema/agenttask.go index 94f0a99b..499ffa97 100755 --- a/ent/schema/agenttask.go +++ b/ent/schema/agenttask.go @@ -30,6 +30,7 @@ func (AgentTask) Fields() []ent.Field { "VALIDATE", "CHANGEPERMS", "APPENDFILE", + "VALIDATOR", ), field.String("args"), field.Int("number"), diff --git a/ent/schema/provisioningstep.go b/ent/schema/provisioningstep.go index 0344fc73..0ca15990 100755 --- a/ent/schema/provisioningstep.go +++ b/ent/schema/provisioningstep.go @@ -26,6 +26,7 @@ func (ProvisioningStep) Fields() []ent.Field { "FileDelete", "FileDownload", "FileExtract", + "Validate", ), field.Int("step_number"), } diff --git a/ent/schema/validations.go b/ent/schema/validations.go index 32b5932b..0e4c56e6 100644 --- a/ent/schema/validations.go +++ b/ent/schema/validations.go @@ -30,6 +30,21 @@ func (Validator) Fields() []ent.Field { } } +type ValidatorConfigBlock struct { + Name string `json:"name" hcl:"name"` + Regex string `json:"name,omitempty" hcl:"regex,optional"` + Ip string `json:"name,omitempty" hcl:"ip,optional"` + Port int + Hostname string `json:"name,omitempty" hcl:"hostname,optional"` + Nameservers []string `json:"name_servers,omitempty" hcl:"name_servers,optional"` + PackageName string `json:"name,omitempty" hcl:"packagename,optional"` + Username string `json:"name,omitempty" hcl:"username,optional"` + Groupname string `json:"name,omitempty" hcl:"groupname,optional"` + Filepath string `json:"name,omitempty" hcl:"filepath,optional"` + ServiceName string `json:"name,omitempty" hcl:"servicename,optional"` + ProcessName string `json:"process_name,omitempty" hcl:"process_name,optional"` +} + // Edges of the AgentTask. func (Validator) Edges() []ent.Edge { return []ent.Edge{ @@ -47,5 +62,6 @@ func (Validator) Edges() []ent.Edge { Unique(), edge.From("Environment", ProvisioningStep.Type). Unique(), + edge.To("Validator", ValidatorBlockType).StructTag(`hcl:"dns,block"`).Unique(), } } diff --git a/grpc/agent/agent.go b/grpc/agent/agent.go index b90aa777..e9a33996 100644 --- a/grpc/agent/agent.go +++ b/grpc/agent/agent.go @@ -271,6 +271,7 @@ func RequestTask(c pb.LaforgeClient) { } switch validatorName { case "net-banner": + // how to determine to run unix vs windows validation? fmt.Println("hi") case "win-registry-hive": fmt.Println("hi") diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index e4ec7637..85c6fbed 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -21,6 +21,9 @@ import ( "strings" "syscall" "time" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" ) func MD5Sum(content string) string { @@ -388,20 +391,47 @@ func UDPOpenTest(socket net.Conn, return_chan chan bool, optional_payload string } func NetICMP(ip string) (bool, error) { // responded (boolean) - // This WILL block the thread! However, agent tasks are on their own threads. - result := exec.Command("ping", "-c", "5", ip) // you can write a ping packet and send it using pure golang, however it's quite complicated and requires more importing of libraries - ps_output, err := result.Output() + // // This WILL block the thread! However, agent tasks are on their own threads. + // result := exec.Command("ping", "-c", "5", ip) // you can write a ping packet and send it using pure golang, however it's quite complicated and requires more importing of libraries + // ps_output, err := result.Output() + // if err != nil { + // return false, err + // } + // fmt.Println(string(ps_output)) + // ps_lines := strings.Split(string(ps_output), "\n") + // for i := 0; i < len(ps_lines); i++ { + // if strings.HasPrefix(ps_lines[i], "5 packets transmitted, 5 received") { // this is pretty jank + // return true, nil + // } + // } + // return false, nil + icmp_conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { return false, err } - fmt.Println(string(ps_output)) - ps_lines := strings.Split(string(ps_output), "\n") - for i := 0; i < len(ps_lines); i++ { - if strings.HasPrefix(ps_lines[i], "5 packets transmitted, 5 received") { // this is pretty jank - return true, nil + defer icmp_conn.Close() + raw_icmp_packet := icmp.Message{ + Type: ipv4.ICMPTypeEcho, + Code: 0, + Body: &icmp.Echo{ + ID: os.Getpid() & 0xffff, + Seq: 1, + Data: []byte("") } } - return false, nil + icmp_packet, err := raw_icmp_packet.Marshal(nil) + if err != nil { + return false, err + } + echo := make([]byte, 1500) + err = icmp_conn.SetReadDeadline(time.Now().Add(10 * time.Second)) + if err != nil { + return false, err + } + _, _, err := icmp_conn.ReadFrom(echo) + if err != nil { + return false, err + } } func FileContentString(filepath string, text string) (bool, error) { // matches diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 38dfaf3f..81ec83c5 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -147,13 +147,13 @@ func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) } func GetRegistry(path string) (bool, error) { // exists (boolean) - registry, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) + path, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) if err != nil { return false, err } - defer registry.Close() + defer path.Close() - s, _, err := registry.GetStringValue("SystemRoot") + s, _, err := path.GetStringValue("SystemRoot") if err != nil { return false, err } diff --git a/grpc/proto/agent_proto.pb.go b/grpc/proto/agent_proto.pb.go index 1cc41fd5..e3ec49ad 100644 --- a/grpc/proto/agent_proto.pb.go +++ b/grpc/proto/agent_proto.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 -// protoc v3.6.1 +// protoc v3.12.4 // source: agent_proto.proto package proto @@ -36,6 +36,7 @@ const ( TaskReply_VALIDATE TaskReply_Command = 9 TaskReply_CHANGEPERMS TaskReply_Command = 10 TaskReply_APPENDFILE TaskReply_Command = 11 + TaskReply_VALIDATOR TaskReply_Command = 12 // validation task ) // Enum value maps for TaskReply_Command. @@ -53,6 +54,7 @@ var ( 9: "VALIDATE", 10: "CHANGEPERMS", 11: "APPENDFILE", + 12: "VALIDATOR", } TaskReply_Command_value = map[string]int32{ "DEFAULT": 0, @@ -67,6 +69,7 @@ var ( "VALIDATE": 9, "CHANGEPERMS": 10, "APPENDFILE": 11, + "VALIDATOR": 12, } ) @@ -573,13 +576,13 @@ var file_agent_proto_proto_rawDesc = []byte{ 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x22, 0x2a, 0x0a, 0x0b, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x49, 0x64, 0x22, 0xa5, 0x02, 0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x49, 0x64, 0x22, 0xb4, 0x02, 0x0a, 0x09, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, - 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0xb9, + 0x67, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x67, 0x73, 0x22, 0xc8, 0x01, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x42, 0x4f, 0x4f, 0x54, 0x10, 0x02, 0x12, @@ -591,38 +594,39 @@ var file_agent_proto_proto_rawDesc = []byte{ 0x0a, 0x07, 0x45, 0x58, 0x45, 0x43, 0x55, 0x54, 0x45, 0x10, 0x08, 0x12, 0x0c, 0x0a, 0x08, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, 0x10, 0x09, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x50, 0x45, 0x52, 0x4d, 0x53, 0x10, 0x0a, 0x12, 0x0e, 0x0a, 0x0a, 0x41, 0x50, - 0x50, 0x45, 0x4e, 0x44, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x0b, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x54, - 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, - 0x0a, 0x0f, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xea, 0x01, 0x0a, 0x07, 0x6c, 0x61, - 0x66, 0x6f, 0x72, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x72, - 0x74, 0x42, 0x65, 0x61, 0x74, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x18, - 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, - 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, - 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, - 0x22, 0x00, 0x12, 0x52, 0x0a, 0x10, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x54, 0x61, 0x73, 0x6b, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x47, 0x0a, 0x0e, 0x69, 0x6f, 0x2e, 0x61, 0x67, 0x65, - 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x6e, 0x30, 0x63, 0x69, 0x64, 0x65, 0x2f, 0x6c, 0x61, 0x66, - 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x50, 0x45, 0x4e, 0x44, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x0b, 0x12, 0x0d, 0x0a, 0x09, 0x56, 0x41, + 0x4c, 0x49, 0x44, 0x41, 0x54, 0x4f, 0x52, 0x10, 0x0c, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x54, 0x61, + 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x29, 0x0a, + 0x0f, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xea, 0x01, 0x0a, 0x07, 0x6c, 0x61, 0x66, + 0x6f, 0x72, 0x67, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x48, 0x65, 0x61, 0x72, 0x74, + 0x42, 0x65, 0x61, 0x74, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x18, 0x2e, + 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x12, 0x52, 0x0a, 0x10, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x54, 0x61, 0x73, 0x6b, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x47, 0x0a, 0x0e, 0x69, 0x6f, 0x2e, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x0b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x65, 0x6e, 0x30, 0x63, 0x69, 0x64, 0x65, 0x2f, 0x6c, 0x61, 0x66, 0x6f, + 0x72, 0x67, 0x65, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/grpc/server/server.go b/grpc/server/server.go index c0890051..db563806 100644 --- a/grpc/server/server.go +++ b/grpc/server/server.go @@ -7,6 +7,8 @@ import ( "strings" "time" + lc "laforge/ent/schema/agenttask" + "github.com/gen0cide/laforge/ent" "github.com/gen0cide/laforge/ent/agenttask" "github.com/gen0cide/laforge/ent/command" @@ -199,8 +201,11 @@ func (s *Server) InformTaskStatus(ctx context.Context, in *pb.TaskStatusRequest) return &pb.TaskStatusReply{Status: "ERROR"}, nil } output := strings.ReplaceAll(in.GetOutput(), "🔥", "\n") - // server-side validation hook starting agent_command, err := s.Client.Command.Query().Where(command.IDEQ(uuid)).First(ctx) + // server-side validation hook starting + if entAgentTask.Command == lc.CommandValidator() { + // this payload is a response from an agent related to a validation + } err = entAgentTask.Update(). SetState(agenttask.State(in.GetStatus())). diff --git a/loader/parser.go b/loader/parser.go index 17817c51..f4b15c8c 100755 --- a/loader/parser.go +++ b/loader/parser.go @@ -49,14 +49,16 @@ type fileGlobResolver struct { // DefinedConfigs is the stuct to hold in all the loading for hcl type DefinedConfigs struct { Filename string - BaseDir string `hcl:"base_dir,optional" json:"base_dir,omitempty"` - IncludePaths []*Include `hcl:"include,block" json:"include_paths,omitempty"` - DefinedCompetitions []*ent.Competition `hcl:"competition,block" json:"competitions,omitempty"` - DefinedHosts []*ent.Host `hcl:"host,block" json:"hosts,omitempty"` - DefinedNetworks []*ent.Network `hcl:"network,block" json:"networks,omitempty"` - DefinedScripts []*ent.Script `hcl:"script,block" json:"scripts,omitempty"` - DefinedCommands []*ent.Command `hcl:"command,block" json:"defined_commands,omitempty"` - DefinedDNSRecords []*ent.DNSRecord `hcl:"dns_record,block" json:"defined_dns_records,omitempty"` + BaseDir string `hcl:"base_dir,optional" json:"base_dir,omitempty"` + IncludePaths []*Include `hcl:"include,block" json:"include_paths,omitempty"` + DefinedCompetitions []*ent.Competition `hcl:"competition,block" json:"competitions,omitempty"` + DefinedHosts []*ent.Host `hcl:"host,block" json:"hosts,omitempty"` + DefinedNetworks []*ent.Network `hcl:"network,block" json:"networks,omitempty"` + DefinedScripts []*ent.Script `hcl:"script,block" json:"scripts,omitempty"` + DefinedCommands []*ent.Command `hcl:"command,block" json:"defined_commands,omitempty"` + DefinedDNSRecords []*ent.DNSRecord `hcl:"dns_record,block" json:"defined_dns_records,omitempty"` + // specifically for validations + DefinedValidations []*ent.ValidatorConfigBlock `hcl:"validator,block" json:"defined_validators,omitempty"` DefinedEnvironments []*ent.Environment `hcl:"environment,block" json:"environments,omitempty"` DefinedFileDownload []*ent.FileDownload `hcl:"file_download,block" json:"file_download,omitempty"` DefinedFileDelete []*ent.FileDelete `hcl:"file_delete,block" json:"file_delete,omitempty"` @@ -1498,5 +1500,4 @@ func validateHostDependencies(ctx context.Context, client *ent.Client, log *logg func validator(ctx context.Context, client *ent.Client, log *logging.Logger, uncheckedHostDependencies []*ent.HostDependency, envHclID string) ([]*ent.HostDependency, error) { - -} \ No newline at end of file +} diff --git a/planner/build.go b/planner/build.go index 76d7ba88..0e26bf21 100755 --- a/planner/build.go +++ b/planner/build.go @@ -731,6 +731,24 @@ func execStep(client *ent.Client, logger *logging.Logger, ctx context.Context, e logger.Log.Errorf("failed Creating Agent Task for File Extract: %v", err) return err } + case provisioningstep.TypeValidate: + // entFileExtract, err := entStep.QueryProvisioningStepToFileExtract().Only(ctx) + // if err != nil { + // logger.Log.Errorf("failed querying File Extract for Provioning Step: %v", err) + // return err + // } + _, err = client.AgentTask.Create(). + SetCommand(agenttask.CommandVALIDATE). + SetArgs(entFileExtract.Source + "💔" + entFileExtract.Destination). // args for the validation + SetNumber(taskCount). + SetState(agenttask.StateAWAITING). + SetAgentTaskToProvisionedHost(entProvisionedHost). + SetAgentTaskToProvisioningStep(entStep). + Save(ctx) + if err != nil { + logger.Log.Errorf("failed Creating Agent Task for File Extract: %v", err) + return err + } case provisioningstep.TypeDNSRecord: break default: diff --git a/validation/needs_name.go b/validation/needs_name.go new file mode 100644 index 00000000..c72bcf52 --- /dev/null +++ b/validation/needs_name.go @@ -0,0 +1,8 @@ +// - Make new validation foler/package that will be able to take in a Provisoning Step, figure out what validators it wants, create the proper agent tasks, +// and once it recives the agent tasks output validate things accordingly + +// accept pb.ProvisioningStep +// spawn AgentTask threads according to validations read from provisioningstep +// after agenttask threads are done, make sure they were successful + +package validation From 50c3fee4ad40d81eb2988d0f9c814c43d4063c94 Mon Sep 17 00:00:00 2001 From: Curtis Fowler Date: Wed, 2 Feb 2022 21:07:14 -0500 Subject: [PATCH 14/25] fix: agent_unix ping --- grpc/agent/agent_unix.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/grpc/agent/agent_unix.go b/grpc/agent/agent_unix.go index 85c6fbed..6be05cad 100644 --- a/grpc/agent/agent_unix.go +++ b/grpc/agent/agent_unix.go @@ -414,12 +414,12 @@ func NetICMP(ip string) (bool, error) { // responded (boolean) Type: ipv4.ICMPTypeEcho, Code: 0, Body: &icmp.Echo{ - ID: os.Getpid() & 0xffff, - Seq: 1, - Data: []byte("") - } + ID: os.Getpid() & 0xffff, + Seq: 1, + Data: []byte(""), + }, } - icmp_packet, err := raw_icmp_packet.Marshal(nil) + _, err = raw_icmp_packet.Marshal(nil) if err != nil { return false, err } @@ -428,10 +428,14 @@ func NetICMP(ip string) (bool, error) { // responded (boolean) if err != nil { return false, err } - _, _, err := icmp_conn.ReadFrom(echo) + pkt, _, err := icmp_conn.ReadFrom(echo) + if pkt != 0 { + return true, nil + } if err != nil { return false, err } + return false, nil } func FileContentString(filepath string, text string) (bool, error) { // matches From 2cea681f54b299ea5d392b143384a40d3c7f3de5 Mon Sep 17 00:00:00 2001 From: Francisco Perez Date: Thu, 3 Feb 2022 14:28:15 -0500 Subject: [PATCH 15/25] adding functions --- grpc/agent/agent_windows.go | 41 ++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/grpc/agent/agent_windows.go b/grpc/agent/agent_windows.go index 81ec83c5..d217ee28 100644 --- a/grpc/agent/agent_windows.go +++ b/grpc/agent/agent_windows.go @@ -1,11 +1,12 @@ -windows +// windows +//go:build windows // +build windows -package p +package main + // package main // uncomment for testing funcs below import ( - "golang.org/x/sys/windows/registry" "crypto/md5" "fmt" "io" @@ -17,6 +18,7 @@ import ( s "os" "os/exec" user "os/user" + "path/filepath" "strconv" "strings" @@ -146,19 +148,19 @@ func GetNetBanner(portnum int64) (bool, error) { // exists (boolean) return true, nil } -func GetRegistry(path string) (bool, error) { // exists (boolean) - path, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) - if err != nil { - return false, err - } - defer path.Close() +// func GetRegistry(path string) (bool, error) { // exists (boolean) +// path, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) +// if err != nil { +// return false, err +// } +// defer path.Close() - s, _, err := path.GetStringValue("SystemRoot") - if err != nil { - return false, err - } - return true, nil -} +// s, _, err := path.GetStringValue("SystemRoot") +// if err != nil { +// return false, err +// } +// return true, nil +// } func NetHttpContentRegex(full_url string) (string, error) { // content hash (string) net_resp, err := http.Get(full_url) @@ -231,7 +233,8 @@ func UserExists(user_name string) (bool, error) { // exists (boolean } func UserGroupMember(user_name string, group_name string) (bool, error) { // is in the group or not (boolean) - fmt.Println(user.Lookup(user_name)) + user.Lookup(user_name) + return false, nil } @@ -354,6 +357,10 @@ func FilePermission(filepath string) (string, error) { // permissions (in the fo func main() { fmt.Println("windows") - fmt.Println(UserExists("piero")) + fmt.Println(UserGroupMember("asdf", "faafsd")) + // fmt.Println(NetICMP("192.168.1.1")) + // fmt.Println(FileContentString("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go", "5646548932")) + // fmt.Println(UserExists("piero")) + // fmt.Println(FilePermission("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) // fmt.Println(FileExists("C:\\Users\\The Power\\Documents\\2021Fall\\CMSC451\\LaForge\\laforge\\grpc\\agent\\agent_windows.go")) } From ded6d193aa065c6bbb533e21a6ec02ad31a09c5e Mon Sep 17 00:00:00 2001 From: Colden Date: Sun, 6 Feb 2022 21:36:34 -0500 Subject: [PATCH 16/25] generated validation ent schema --- ent/agenttask.go | 26 +- ent/agenttask/agenttask.go | 12 +- ent/agenttask/where.go | 28 + ent/agenttask_create.go | 39 + ent/agenttask_query.go | 67 +- ent/agenttask_update.go | 121 ++ ent/client.go | 161 +++ ent/collection.go | 12 + ent/config.go | 1 + ent/edge.go | 32 + ent/ent.go | 2 + ent/hook/hook.go | 13 + ent/migrate/schema.go | 49 +- ent/mutation.go | 1428 +++++++++++++++++++++- ent/node.go | 206 +++- ent/pagination.go | 228 ++++ ent/predicate/predicate.go | 3 + ent/provisioningstep/provisioningstep.go | 3 +- ent/runtime.go | 19 + ent/schema-viz.html | 58 +- ent/schema/agenttask.go | 1 + ent/schema/script.go | 1 + ent/schema/validations.go | 67 - ent/script.go | 36 +- ent/script/script.go | 10 + ent/script/where.go | 28 + ent/script_create.go | 40 + ent/script_query.go | 70 +- ent/script_update.go | 121 ++ ent/tx.go | 3 + go.mod | 1 + go.sum | 2 + 32 files changed, 2752 insertions(+), 136 deletions(-) delete mode 100644 ent/schema/validations.go diff --git a/ent/agenttask.go b/ent/agenttask.go index 8629ddda..f350bb54 100755 --- a/ent/agenttask.go +++ b/ent/agenttask.go @@ -10,6 +10,7 @@ import ( "github.com/gen0cide/laforge/ent/agenttask" "github.com/gen0cide/laforge/ent/provisionedhost" "github.com/gen0cide/laforge/ent/provisioningstep" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" ) @@ -41,6 +42,8 @@ type AgentTask struct { HCLAgentTaskToProvisionedHost *ProvisionedHost `json:"AgentTaskToProvisionedHost,omitempty"` // AgentTaskToAdhocPlan holds the value of the AgentTaskToAdhocPlan edge. HCLAgentTaskToAdhocPlan []*AdhocPlan `json:"AgentTaskToAdhocPlan,omitempty"` + // AgentTaskToValidation holds the value of the AgentTaskToValidation edge. + HCLAgentTaskToValidation *Validation `json:"AgentTaskToValidation,omitempty"` // agent_task_agent_task_to_provisioning_step *uuid.UUID agent_task_agent_task_to_provisioned_host *uuid.UUID @@ -54,9 +57,11 @@ type AgentTaskEdges struct { AgentTaskToProvisionedHost *ProvisionedHost `json:"AgentTaskToProvisionedHost,omitempty"` // AgentTaskToAdhocPlan holds the value of the AgentTaskToAdhocPlan edge. AgentTaskToAdhocPlan []*AdhocPlan `json:"AgentTaskToAdhocPlan,omitempty"` + // AgentTaskToValidation holds the value of the AgentTaskToValidation edge. + AgentTaskToValidation *Validation `json:"AgentTaskToValidation,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [3]bool + loadedTypes [4]bool } // AgentTaskToProvisioningStepOrErr returns the AgentTaskToProvisioningStep value or an error if the edge @@ -96,6 +101,20 @@ func (e AgentTaskEdges) AgentTaskToAdhocPlanOrErr() ([]*AdhocPlan, error) { return nil, &NotLoadedError{edge: "AgentTaskToAdhocPlan"} } +// AgentTaskToValidationOrErr returns the AgentTaskToValidation value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e AgentTaskEdges) AgentTaskToValidationOrErr() (*Validation, error) { + if e.loadedTypes[3] { + if e.AgentTaskToValidation == nil { + // The edge AgentTaskToValidation was loaded in eager-loading, + // but was not found. + return nil, &NotFoundError{label: validation.Label} + } + return e.AgentTaskToValidation, nil + } + return nil, &NotLoadedError{edge: "AgentTaskToValidation"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*AgentTask) scanValues(columns []string) ([]interface{}, error) { values := make([]interface{}, len(columns)) @@ -202,6 +221,11 @@ func (at *AgentTask) QueryAgentTaskToAdhocPlan() *AdhocPlanQuery { return (&AgentTaskClient{config: at.config}).QueryAgentTaskToAdhocPlan(at) } +// QueryAgentTaskToValidation queries the "AgentTaskToValidation" edge of the AgentTask entity. +func (at *AgentTask) QueryAgentTaskToValidation() *ValidationQuery { + return (&AgentTaskClient{config: at.config}).QueryAgentTaskToValidation(at) +} + // Update returns a builder for updating this AgentTask. // Note that you need to call AgentTask.Unwrap() before calling this method if this AgentTask // was returned from a transaction, and the transaction was committed or rolled back. diff --git a/ent/agenttask/agenttask.go b/ent/agenttask/agenttask.go index 7e7be785..de02d887 100755 --- a/ent/agenttask/agenttask.go +++ b/ent/agenttask/agenttask.go @@ -33,6 +33,8 @@ const ( EdgeAgentTaskToProvisionedHost = "AgentTaskToProvisionedHost" // EdgeAgentTaskToAdhocPlan holds the string denoting the agenttasktoadhocplan edge name in mutations. EdgeAgentTaskToAdhocPlan = "AgentTaskToAdhocPlan" + // EdgeAgentTaskToValidation holds the string denoting the agenttasktovalidation edge name in mutations. + EdgeAgentTaskToValidation = "AgentTaskToValidation" // Table holds the table name of the agenttask in the database. Table = "agent_tasks" // AgentTaskToProvisioningStepTable is the table that holds the AgentTaskToProvisioningStep relation/edge. @@ -56,6 +58,13 @@ const ( AgentTaskToAdhocPlanInverseTable = "adhoc_plans" // AgentTaskToAdhocPlanColumn is the table column denoting the AgentTaskToAdhocPlan relation/edge. AgentTaskToAdhocPlanColumn = "adhoc_plan_adhoc_plan_to_agent_task" + // AgentTaskToValidationTable is the table that holds the AgentTaskToValidation relation/edge. + AgentTaskToValidationTable = "validations" + // AgentTaskToValidationInverseTable is the table name for the Validation entity. + // It exists in this package in order to avoid circular dependency with the "validation" package. + AgentTaskToValidationInverseTable = "validations" + // AgentTaskToValidationColumn is the table column denoting the AgentTaskToValidation relation/edge. + AgentTaskToValidationColumn = "agent_task_agent_task_to_validation" ) // Columns holds all SQL columns for agenttask fields. @@ -117,6 +126,7 @@ const ( CommandVALIDATE Command = "VALIDATE" CommandCHANGEPERMS Command = "CHANGEPERMS" CommandAPPENDFILE Command = "APPENDFILE" + CommandVALIDATOR Command = "VALIDATOR" ) func (c Command) String() string { @@ -126,7 +136,7 @@ func (c Command) String() string { // CommandValidator is a validator for the "command" field enum values. It is called by the builders before save. func CommandValidator(c Command) error { switch c { - case CommandDEFAULT, CommandDELETE, CommandREBOOT, CommandEXTRACT, CommandDOWNLOAD, CommandCREATEUSER, CommandCREATEUSERPASS, CommandADDTOGROUP, CommandEXECUTE, CommandVALIDATE, CommandCHANGEPERMS, CommandAPPENDFILE: + case CommandDEFAULT, CommandDELETE, CommandREBOOT, CommandEXTRACT, CommandDOWNLOAD, CommandCREATEUSER, CommandCREATEUSERPASS, CommandADDTOGROUP, CommandEXECUTE, CommandVALIDATE, CommandCHANGEPERMS, CommandAPPENDFILE, CommandVALIDATOR: return nil default: return fmt.Errorf("agenttask: invalid enum value for command field: %q", c) diff --git a/ent/agenttask/where.go b/ent/agenttask/where.go index 9539f45a..ab94bb4e 100755 --- a/ent/agenttask/where.go +++ b/ent/agenttask/where.go @@ -709,6 +709,34 @@ func HasAgentTaskToAdhocPlanWith(preds ...predicate.AdhocPlan) predicate.AgentTa }) } +// HasAgentTaskToValidation applies the HasEdge predicate on the "AgentTaskToValidation" edge. +func HasAgentTaskToValidation() predicate.AgentTask { + return predicate.AgentTask(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(AgentTaskToValidationTable, FieldID), + sqlgraph.Edge(sqlgraph.O2O, false, AgentTaskToValidationTable, AgentTaskToValidationColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasAgentTaskToValidationWith applies the HasEdge predicate on the "AgentTaskToValidation" edge with a given conditions (other predicates). +func HasAgentTaskToValidationWith(preds ...predicate.Validation) predicate.AgentTask { + return predicate.AgentTask(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(AgentTaskToValidationInverseTable, FieldID), + sqlgraph.Edge(sqlgraph.O2O, false, AgentTaskToValidationTable, AgentTaskToValidationColumn), + ) + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.AgentTask) predicate.AgentTask { return predicate.AgentTask(func(s *sql.Selector) { diff --git a/ent/agenttask_create.go b/ent/agenttask_create.go index 4c3197f1..9875b90f 100755 --- a/ent/agenttask_create.go +++ b/ent/agenttask_create.go @@ -13,6 +13,7 @@ import ( "github.com/gen0cide/laforge/ent/agenttask" "github.com/gen0cide/laforge/ent/provisionedhost" "github.com/gen0cide/laforge/ent/provisioningstep" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" ) @@ -126,6 +127,25 @@ func (atc *AgentTaskCreate) AddAgentTaskToAdhocPlan(a ...*AdhocPlan) *AgentTaskC return atc.AddAgentTaskToAdhocPlanIDs(ids...) } +// SetAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID. +func (atc *AgentTaskCreate) SetAgentTaskToValidationID(id uuid.UUID) *AgentTaskCreate { + atc.mutation.SetAgentTaskToValidationID(id) + return atc +} + +// SetNillableAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID if the given value is not nil. +func (atc *AgentTaskCreate) SetNillableAgentTaskToValidationID(id *uuid.UUID) *AgentTaskCreate { + if id != nil { + atc = atc.SetAgentTaskToValidationID(*id) + } + return atc +} + +// SetAgentTaskToValidation sets the "AgentTaskToValidation" edge to the Validation entity. +func (atc *AgentTaskCreate) SetAgentTaskToValidation(v *Validation) *AgentTaskCreate { + return atc.SetAgentTaskToValidationID(v.ID) +} + // Mutation returns the AgentTaskMutation object of the builder. func (atc *AgentTaskCreate) Mutation() *AgentTaskMutation { return atc.mutation @@ -383,6 +403,25 @@ func (atc *AgentTaskCreate) createSpec() (*AgentTask, *sqlgraph.CreateSpec) { } _spec.Edges = append(_spec.Edges, edge) } + if nodes := atc.mutation.AgentTaskToValidationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2O, + Inverse: false, + Table: agenttask.AgentTaskToValidationTable, + Columns: []string{agenttask.AgentTaskToValidationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: validation.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges = append(_spec.Edges, edge) + } return _node, _spec } diff --git a/ent/agenttask_query.go b/ent/agenttask_query.go index b5f74a01..3968a7e9 100755 --- a/ent/agenttask_query.go +++ b/ent/agenttask_query.go @@ -17,6 +17,7 @@ import ( "github.com/gen0cide/laforge/ent/predicate" "github.com/gen0cide/laforge/ent/provisionedhost" "github.com/gen0cide/laforge/ent/provisioningstep" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" ) @@ -33,6 +34,7 @@ type AgentTaskQuery struct { withAgentTaskToProvisioningStep *ProvisioningStepQuery withAgentTaskToProvisionedHost *ProvisionedHostQuery withAgentTaskToAdhocPlan *AdhocPlanQuery + withAgentTaskToValidation *ValidationQuery withFKs bool // intermediate query (i.e. traversal path). sql *sql.Selector @@ -136,6 +138,28 @@ func (atq *AgentTaskQuery) QueryAgentTaskToAdhocPlan() *AdhocPlanQuery { return query } +// QueryAgentTaskToValidation chains the current query on the "AgentTaskToValidation" edge. +func (atq *AgentTaskQuery) QueryAgentTaskToValidation() *ValidationQuery { + query := &ValidationQuery{config: atq.config} + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := atq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := atq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(agenttask.Table, agenttask.FieldID, selector), + sqlgraph.To(validation.Table, validation.FieldID), + sqlgraph.Edge(sqlgraph.O2O, false, agenttask.AgentTaskToValidationTable, agenttask.AgentTaskToValidationColumn), + ) + fromU = sqlgraph.SetNeighbors(atq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first AgentTask entity from the query. // Returns a *NotFoundError when no AgentTask was found. func (atq *AgentTaskQuery) First(ctx context.Context) (*AgentTask, error) { @@ -320,6 +344,7 @@ func (atq *AgentTaskQuery) Clone() *AgentTaskQuery { withAgentTaskToProvisioningStep: atq.withAgentTaskToProvisioningStep.Clone(), withAgentTaskToProvisionedHost: atq.withAgentTaskToProvisionedHost.Clone(), withAgentTaskToAdhocPlan: atq.withAgentTaskToAdhocPlan.Clone(), + withAgentTaskToValidation: atq.withAgentTaskToValidation.Clone(), // clone intermediate query. sql: atq.sql.Clone(), path: atq.path, @@ -359,6 +384,17 @@ func (atq *AgentTaskQuery) WithAgentTaskToAdhocPlan(opts ...func(*AdhocPlanQuery return atq } +// WithAgentTaskToValidation tells the query-builder to eager-load the nodes that are connected to +// the "AgentTaskToValidation" edge. The optional arguments are used to configure the query builder of the edge. +func (atq *AgentTaskQuery) WithAgentTaskToValidation(opts ...func(*ValidationQuery)) *AgentTaskQuery { + query := &ValidationQuery{config: atq.config} + for _, opt := range opts { + opt(query) + } + atq.withAgentTaskToValidation = query + return atq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -425,10 +461,11 @@ func (atq *AgentTaskQuery) sqlAll(ctx context.Context) ([]*AgentTask, error) { nodes = []*AgentTask{} withFKs = atq.withFKs _spec = atq.querySpec() - loadedTypes = [3]bool{ + loadedTypes = [4]bool{ atq.withAgentTaskToProvisioningStep != nil, atq.withAgentTaskToProvisionedHost != nil, atq.withAgentTaskToAdhocPlan != nil, + atq.withAgentTaskToValidation != nil, } ) if atq.withAgentTaskToProvisioningStep != nil || atq.withAgentTaskToProvisionedHost != nil { @@ -544,6 +581,34 @@ func (atq *AgentTaskQuery) sqlAll(ctx context.Context) ([]*AgentTask, error) { } } + if query := atq.withAgentTaskToValidation; query != nil { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[uuid.UUID]*AgentTask) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + } + query.withFKs = true + query.Where(predicate.Validation(func(s *sql.Selector) { + s.Where(sql.InValues(agenttask.AgentTaskToValidationColumn, fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return nil, err + } + for _, n := range neighbors { + fk := n.agent_task_agent_task_to_validation + if fk == nil { + return nil, fmt.Errorf(`foreign-key "agent_task_agent_task_to_validation" is nil for node %v`, n.ID) + } + node, ok := nodeids[*fk] + if !ok { + return nil, fmt.Errorf(`unexpected foreign-key "agent_task_agent_task_to_validation" returned %v for node %v`, *fk, n.ID) + } + node.Edges.AgentTaskToValidation = n + } + } + return nodes, nil } diff --git a/ent/agenttask_update.go b/ent/agenttask_update.go index fe122b72..ae5c97ad 100755 --- a/ent/agenttask_update.go +++ b/ent/agenttask_update.go @@ -15,6 +15,7 @@ import ( "github.com/gen0cide/laforge/ent/predicate" "github.com/gen0cide/laforge/ent/provisionedhost" "github.com/gen0cide/laforge/ent/provisioningstep" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" ) @@ -135,6 +136,25 @@ func (atu *AgentTaskUpdate) AddAgentTaskToAdhocPlan(a ...*AdhocPlan) *AgentTaskU return atu.AddAgentTaskToAdhocPlanIDs(ids...) } +// SetAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID. +func (atu *AgentTaskUpdate) SetAgentTaskToValidationID(id uuid.UUID) *AgentTaskUpdate { + atu.mutation.SetAgentTaskToValidationID(id) + return atu +} + +// SetNillableAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID if the given value is not nil. +func (atu *AgentTaskUpdate) SetNillableAgentTaskToValidationID(id *uuid.UUID) *AgentTaskUpdate { + if id != nil { + atu = atu.SetAgentTaskToValidationID(*id) + } + return atu +} + +// SetAgentTaskToValidation sets the "AgentTaskToValidation" edge to the Validation entity. +func (atu *AgentTaskUpdate) SetAgentTaskToValidation(v *Validation) *AgentTaskUpdate { + return atu.SetAgentTaskToValidationID(v.ID) +} + // Mutation returns the AgentTaskMutation object of the builder. func (atu *AgentTaskUpdate) Mutation() *AgentTaskMutation { return atu.mutation @@ -173,6 +193,12 @@ func (atu *AgentTaskUpdate) RemoveAgentTaskToAdhocPlan(a ...*AdhocPlan) *AgentTa return atu.RemoveAgentTaskToAdhocPlanIDs(ids...) } +// ClearAgentTaskToValidation clears the "AgentTaskToValidation" edge to the Validation entity. +func (atu *AgentTaskUpdate) ClearAgentTaskToValidation() *AgentTaskUpdate { + atu.mutation.ClearAgentTaskToValidation() + return atu +} + // Save executes the query and returns the number of nodes affected by the update operation. func (atu *AgentTaskUpdate) Save(ctx context.Context) (int, error) { var ( @@ -442,6 +468,41 @@ func (atu *AgentTaskUpdate) sqlSave(ctx context.Context) (n int, err error) { } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if atu.mutation.AgentTaskToValidationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2O, + Inverse: false, + Table: agenttask.AgentTaskToValidationTable, + Columns: []string{agenttask.AgentTaskToValidationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: validation.FieldID, + }, + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := atu.mutation.AgentTaskToValidationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2O, + Inverse: false, + Table: agenttask.AgentTaskToValidationTable, + Columns: []string{agenttask.AgentTaskToValidationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: validation.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } if n, err = sqlgraph.UpdateNodes(ctx, atu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{agenttask.Label} @@ -565,6 +626,25 @@ func (atuo *AgentTaskUpdateOne) AddAgentTaskToAdhocPlan(a ...*AdhocPlan) *AgentT return atuo.AddAgentTaskToAdhocPlanIDs(ids...) } +// SetAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID. +func (atuo *AgentTaskUpdateOne) SetAgentTaskToValidationID(id uuid.UUID) *AgentTaskUpdateOne { + atuo.mutation.SetAgentTaskToValidationID(id) + return atuo +} + +// SetNillableAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by ID if the given value is not nil. +func (atuo *AgentTaskUpdateOne) SetNillableAgentTaskToValidationID(id *uuid.UUID) *AgentTaskUpdateOne { + if id != nil { + atuo = atuo.SetAgentTaskToValidationID(*id) + } + return atuo +} + +// SetAgentTaskToValidation sets the "AgentTaskToValidation" edge to the Validation entity. +func (atuo *AgentTaskUpdateOne) SetAgentTaskToValidation(v *Validation) *AgentTaskUpdateOne { + return atuo.SetAgentTaskToValidationID(v.ID) +} + // Mutation returns the AgentTaskMutation object of the builder. func (atuo *AgentTaskUpdateOne) Mutation() *AgentTaskMutation { return atuo.mutation @@ -603,6 +683,12 @@ func (atuo *AgentTaskUpdateOne) RemoveAgentTaskToAdhocPlan(a ...*AdhocPlan) *Age return atuo.RemoveAgentTaskToAdhocPlanIDs(ids...) } +// ClearAgentTaskToValidation clears the "AgentTaskToValidation" edge to the Validation entity. +func (atuo *AgentTaskUpdateOne) ClearAgentTaskToValidation() *AgentTaskUpdateOne { + atuo.mutation.ClearAgentTaskToValidation() + return atuo +} + // Select allows selecting one or more fields (columns) of the returned entity. // The default is selecting all fields defined in the entity schema. func (atuo *AgentTaskUpdateOne) Select(field string, fields ...string) *AgentTaskUpdateOne { @@ -896,6 +982,41 @@ func (atuo *AgentTaskUpdateOne) sqlSave(ctx context.Context) (_node *AgentTask, } _spec.Edges.Add = append(_spec.Edges.Add, edge) } + if atuo.mutation.AgentTaskToValidationCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2O, + Inverse: false, + Table: agenttask.AgentTaskToValidationTable, + Columns: []string{agenttask.AgentTaskToValidationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: validation.FieldID, + }, + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := atuo.mutation.AgentTaskToValidationIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.O2O, + Inverse: false, + Table: agenttask.AgentTaskToValidationTable, + Columns: []string{agenttask.AgentTaskToValidationColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: validation.FieldID, + }, + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } _node = &AgentTask{config: atuo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/ent/client.go b/ent/client.go index fb405c92..4a15be4e 100755 --- a/ent/client.go +++ b/ent/client.go @@ -45,6 +45,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql" @@ -126,6 +127,8 @@ type Client struct { Token *TokenClient // User is the client for interacting with the User builders. User *UserClient + // Validation is the client for interacting with the Validation builders. + Validation *ValidationClient } // NewClient creates a new client configured with the given options. @@ -174,6 +177,7 @@ func (c *Client) init() { c.Team = NewTeamClient(c.config) c.Token = NewTokenClient(c.config) c.User = NewUserClient(c.config) + c.Validation = NewValidationClient(c.config) } // Open opens a database/sql.DB specified by the driver name and @@ -242,6 +246,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Team: NewTeamClient(cfg), Token: NewTokenClient(cfg), User: NewUserClient(cfg), + Validation: NewValidationClient(cfg), }, nil } @@ -295,6 +300,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Team: NewTeamClient(cfg), Token: NewTokenClient(cfg), User: NewUserClient(cfg), + Validation: NewValidationClient(cfg), }, nil } @@ -359,6 +365,7 @@ func (c *Client) Use(hooks ...Hook) { c.Team.Use(hooks...) c.Token.Use(hooks...) c.User.Use(hooks...) + c.Validation.Use(hooks...) } // AdhocPlanClient is a client for the AdhocPlan schema. @@ -802,6 +809,22 @@ func (c *AgentTaskClient) QueryAgentTaskToAdhocPlan(at *AgentTask) *AdhocPlanQue return query } +// QueryAgentTaskToValidation queries the AgentTaskToValidation edge of a AgentTask. +func (c *AgentTaskClient) QueryAgentTaskToValidation(at *AgentTask) *ValidationQuery { + query := &ValidationQuery{config: c.config} + query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { + id := at.ID + step := sqlgraph.NewStep( + sqlgraph.From(agenttask.Table, agenttask.FieldID, id), + sqlgraph.To(validation.Table, validation.FieldID), + sqlgraph.Edge(sqlgraph.O2O, false, agenttask.AgentTaskToValidationTable, agenttask.AgentTaskToValidationColumn), + ) + fromV = sqlgraph.Neighbors(at.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *AgentTaskClient) Hooks() []Hook { return c.hooks.AgentTask @@ -4870,6 +4893,22 @@ func (c *ScriptClient) QueryScriptToEnvironment(s *Script) *EnvironmentQuery { return query } +// QueryScriptToValidation queries the ScriptToValidation edge of a Script. +func (c *ScriptClient) QueryScriptToValidation(s *Script) *ValidationQuery { + query := &ValidationQuery{config: c.config} + query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { + id := s.ID + step := sqlgraph.NewStep( + sqlgraph.From(script.Table, script.FieldID, id), + sqlgraph.To(validation.Table, validation.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, script.ScriptToValidationTable, script.ScriptToValidationColumn), + ) + fromV = sqlgraph.Neighbors(s.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *ScriptClient) Hooks() []Hook { return c.hooks.Script @@ -5734,3 +5773,125 @@ func (c *UserClient) QueryUserToEnvironment(u *User) *EnvironmentQuery { func (c *UserClient) Hooks() []Hook { return c.hooks.User } + +// ValidationClient is a client for the Validation schema. +type ValidationClient struct { + config +} + +// NewValidationClient returns a client for the Validation from the given config. +func NewValidationClient(c config) *ValidationClient { + return &ValidationClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `validation.Hooks(f(g(h())))`. +func (c *ValidationClient) Use(hooks ...Hook) { + c.hooks.Validation = append(c.hooks.Validation, hooks...) +} + +// Create returns a create builder for Validation. +func (c *ValidationClient) Create() *ValidationCreate { + mutation := newValidationMutation(c.config, OpCreate) + return &ValidationCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Validation entities. +func (c *ValidationClient) CreateBulk(builders ...*ValidationCreate) *ValidationCreateBulk { + return &ValidationCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Validation. +func (c *ValidationClient) Update() *ValidationUpdate { + mutation := newValidationMutation(c.config, OpUpdate) + return &ValidationUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ValidationClient) UpdateOne(v *Validation) *ValidationUpdateOne { + mutation := newValidationMutation(c.config, OpUpdateOne, withValidation(v)) + return &ValidationUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ValidationClient) UpdateOneID(id uuid.UUID) *ValidationUpdateOne { + mutation := newValidationMutation(c.config, OpUpdateOne, withValidationID(id)) + return &ValidationUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Validation. +func (c *ValidationClient) Delete() *ValidationDelete { + mutation := newValidationMutation(c.config, OpDelete) + return &ValidationDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a delete builder for the given entity. +func (c *ValidationClient) DeleteOne(v *Validation) *ValidationDeleteOne { + return c.DeleteOneID(v.ID) +} + +// DeleteOneID returns a delete builder for the given id. +func (c *ValidationClient) DeleteOneID(id uuid.UUID) *ValidationDeleteOne { + builder := c.Delete().Where(validation.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ValidationDeleteOne{builder} +} + +// Query returns a query builder for Validation. +func (c *ValidationClient) Query() *ValidationQuery { + return &ValidationQuery{ + config: c.config, + } +} + +// Get returns a Validation entity by its id. +func (c *ValidationClient) Get(ctx context.Context, id uuid.UUID) (*Validation, error) { + return c.Query().Where(validation.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ValidationClient) GetX(ctx context.Context, id uuid.UUID) *Validation { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// QueryValidationToAgentTask queries the ValidationToAgentTask edge of a Validation. +func (c *ValidationClient) QueryValidationToAgentTask(v *Validation) *AgentTaskQuery { + query := &AgentTaskQuery{config: c.config} + query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { + id := v.ID + step := sqlgraph.NewStep( + sqlgraph.From(validation.Table, validation.FieldID, id), + sqlgraph.To(agenttask.Table, agenttask.FieldID), + sqlgraph.Edge(sqlgraph.O2O, true, validation.ValidationToAgentTaskTable, validation.ValidationToAgentTaskColumn), + ) + fromV = sqlgraph.Neighbors(v.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// QueryValidationToScript queries the ValidationToScript edge of a Validation. +func (c *ValidationClient) QueryValidationToScript(v *Validation) *ScriptQuery { + query := &ScriptQuery{config: c.config} + query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { + id := v.ID + step := sqlgraph.NewStep( + sqlgraph.From(validation.Table, validation.FieldID, id), + sqlgraph.To(script.Table, script.FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, validation.ValidationToScriptTable, validation.ValidationToScriptColumn), + ) + fromV = sqlgraph.Neighbors(v.driver.Dialect(), step) + return fromV, nil + } + return query +} + +// Hooks returns the client hooks. +func (c *ValidationClient) Hooks() []Hook { + return c.hooks.Validation +} diff --git a/ent/collection.go b/ent/collection.go index 79b91862..6c1d8af9 100755 --- a/ent/collection.go +++ b/ent/collection.go @@ -427,3 +427,15 @@ func (u *UserQuery) CollectFields(ctx context.Context, satisfies ...string) *Use func (u *UserQuery) collectField(ctx *graphql.OperationContext, field graphql.CollectedField, satisfies ...string) *UserQuery { return u } + +// CollectFields tells the query-builder to eagerly load connected nodes by resolver context. +func (v *ValidationQuery) CollectFields(ctx context.Context, satisfies ...string) *ValidationQuery { + if fc := graphql.GetFieldContext(ctx); fc != nil { + v = v.collectField(graphql.GetOperationContext(ctx), fc.Field, satisfies...) + } + return v +} + +func (v *ValidationQuery) collectField(ctx *graphql.OperationContext, field graphql.CollectedField, satisfies ...string) *ValidationQuery { + return v +} diff --git a/ent/config.go b/ent/config.go index a31d8c1d..774953f4 100755 --- a/ent/config.go +++ b/ent/config.go @@ -59,6 +59,7 @@ type hooks struct { Team []ent.Hook Token []ent.Hook User []ent.Hook + Validation []ent.Hook } // Options applies the options on the config object. diff --git a/ent/edge.go b/ent/edge.go index 0552d3d8..0423956c 100755 --- a/ent/edge.go +++ b/ent/edge.go @@ -92,6 +92,14 @@ func (at *AgentTask) AgentTaskToAdhocPlan(ctx context.Context) ([]*AdhocPlan, er return result, err } +func (at *AgentTask) AgentTaskToValidation(ctx context.Context) (*Validation, error) { + result, err := at.Edges.AgentTaskToValidationOrErr() + if IsNotLoaded(err) { + result, err = at.QueryAgentTaskToValidation().Only(ctx) + } + return result, MaskNotFound(err) +} + func (au *AuthUser) AuthUserToToken(ctx context.Context) ([]*Token, error) { result, err := au.Edges.AuthUserToTokenOrErr() if IsNotLoaded(err) { @@ -956,6 +964,14 @@ func (s *Script) ScriptToEnvironment(ctx context.Context) (*Environment, error) return result, MaskNotFound(err) } +func (s *Script) ScriptToValidation(ctx context.Context) (*Validation, error) { + result, err := s.Edges.ScriptToValidationOrErr() + if IsNotLoaded(err) { + result, err = s.QueryScriptToValidation().Only(ctx) + } + return result, MaskNotFound(err) +} + func (st *ServerTask) ServerTaskToAuthUser(ctx context.Context) (*AuthUser, error) { result, err := st.Edges.ServerTaskToAuthUserOrErr() if IsNotLoaded(err) { @@ -1115,3 +1131,19 @@ func (u *User) UserToEnvironment(ctx context.Context) ([]*Environment, error) { } return result, err } + +func (v *Validation) ValidationToAgentTask(ctx context.Context) (*AgentTask, error) { + result, err := v.Edges.ValidationToAgentTaskOrErr() + if IsNotLoaded(err) { + result, err = v.QueryValidationToAgentTask().Only(ctx) + } + return result, MaskNotFound(err) +} + +func (v *Validation) ValidationToScript(ctx context.Context) ([]*Script, error) { + result, err := v.Edges.ValidationToScriptOrErr() + if IsNotLoaded(err) { + result, err = v.QueryValidationToScript().All(ctx) + } + return result, err +} diff --git a/ent/ent.go b/ent/ent.go index 807323a8..27014257 100755 --- a/ent/ent.go +++ b/ent/ent.go @@ -43,6 +43,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" ) // ent aliases to avoid import conflicts in user's code. @@ -98,6 +99,7 @@ func columnChecker(table string) func(string) error { team.Table: team.ValidColumn, token.Table: token.ValidColumn, user.Table: user.ValidColumn, + validation.Table: validation.ValidColumn, } check, ok := checks[table] if !ok { diff --git a/ent/hook/hook.go b/ent/hook/hook.go index f439f75d..a4cf37f2 100755 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -464,6 +464,19 @@ func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) return f(ctx, mv) } +// The ValidationFunc type is an adapter to allow the use of ordinary +// function as Validation mutator. +type ValidationFunc func(context.Context, *ent.ValidationMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ValidationFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + mv, ok := m.(*ent.ValidationMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ValidationMutation", m) + } + return f(ctx, mv) +} + // Condition is a hook condition function. type Condition func(context.Context, ent.Mutation) bool diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 9cfa6f66..eb5ae0de 100755 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -84,7 +84,7 @@ var ( // AgentTasksColumns holds the columns for the "agent_tasks" table. AgentTasksColumns = []*schema.Column{ {Name: "id", Type: field.TypeUUID}, - {Name: "command", Type: field.TypeEnum, Enums: []string{"DEFAULT", "DELETE", "REBOOT", "EXTRACT", "DOWNLOAD", "CREATEUSER", "CREATEUSERPASS", "ADDTOGROUP", "EXECUTE", "VALIDATE", "CHANGEPERMS", "APPENDFILE"}}, + {Name: "command", Type: field.TypeEnum, Enums: []string{"DEFAULT", "DELETE", "REBOOT", "EXTRACT", "DOWNLOAD", "CREATEUSER", "CREATEUSERPASS", "ADDTOGROUP", "EXECUTE", "VALIDATE", "CHANGEPERMS", "APPENDFILE", "VALIDATOR"}}, {Name: "args", Type: field.TypeString}, {Name: "number", Type: field.TypeInt}, {Name: "output", Type: field.TypeString, Default: ""}, @@ -764,7 +764,7 @@ var ( // ProvisioningStepsColumns holds the columns for the "provisioning_steps" table. ProvisioningStepsColumns = []*schema.Column{ {Name: "id", Type: field.TypeUUID}, - {Name: "type", Type: field.TypeEnum, Enums: []string{"Script", "Command", "DNSRecord", "FileDelete", "FileDownload", "FileExtract"}}, + {Name: "type", Type: field.TypeEnum, Enums: []string{"Script", "Command", "DNSRecord", "FileDelete", "FileDownload", "FileExtract", "Validate"}}, {Name: "step_number", Type: field.TypeInt}, {Name: "gin_file_middleware_gin_file_middleware_to_provisioning_step", Type: field.TypeUUID, Unique: true, Nullable: true}, {Name: "plan_plan_to_provisioning_step", Type: field.TypeUUID, Unique: true, Nullable: true}, @@ -871,6 +871,7 @@ var ( {Name: "abs_path", Type: field.TypeString}, {Name: "tags", Type: field.TypeJSON}, {Name: "environment_environment_to_script", Type: field.TypeUUID, Nullable: true}, + {Name: "script_script_to_validation", Type: field.TypeUUID, Nullable: true}, } // ScriptsTable holds the schema information for the "scripts" table. ScriptsTable = &schema.Table{ @@ -884,6 +885,12 @@ var ( RefColumns: []*schema.Column{EnvironmentsColumns[0]}, OnDelete: schema.Cascade, }, + { + Symbol: "scripts_validations_ScriptToValidation", + Columns: []*schema.Column{ScriptsColumns[16]}, + RefColumns: []*schema.Column{ValidationsColumns[0]}, + OnDelete: schema.SetNull, + }, }, } // ServerTasksColumns holds the columns for the "server_tasks" table. @@ -1121,6 +1128,41 @@ var ( }, }, } + // ValidationsColumns holds the columns for the "validations" table. + ValidationsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeUUID}, + {Name: "hcl_id", Type: field.TypeString}, + {Name: "validation_type", Type: field.TypeString, Default: ""}, + {Name: "output", Type: field.TypeString, Default: ""}, + {Name: "state", Type: field.TypeEnum, Enums: []string{"AWAITING", "INPROGRESS", "FAILED", "COMPLETE"}}, + {Name: "error_message", Type: field.TypeString, Default: ""}, + {Name: "regex", Type: field.TypeString}, + {Name: "ip", Type: field.TypeString}, + {Name: "port", Type: field.TypeInt}, + {Name: "hostname", Type: field.TypeString}, + {Name: "nameservers", Type: field.TypeJSON}, + {Name: "package_name", Type: field.TypeString}, + {Name: "username", Type: field.TypeString}, + {Name: "group_name", Type: field.TypeString}, + {Name: "field_path", Type: field.TypeString}, + {Name: "service_name", Type: field.TypeString}, + {Name: "process_name", Type: field.TypeString}, + {Name: "agent_task_agent_task_to_validation", Type: field.TypeUUID, Unique: true, Nullable: true}, + } + // ValidationsTable holds the schema information for the "validations" table. + ValidationsTable = &schema.Table{ + Name: "validations", + Columns: ValidationsColumns, + PrimaryKey: []*schema.Column{ValidationsColumns[0]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "validations_agent_tasks_AgentTaskToValidation", + Columns: []*schema.Column{ValidationsColumns[17]}, + RefColumns: []*schema.Column{AgentTasksColumns[0]}, + OnDelete: schema.SetNull, + }, + }, + } // AdhocPlanNextAdhocPlanColumns holds the columns for the "adhoc_plan_NextAdhocPlan" table. AdhocPlanNextAdhocPlanColumns = []*schema.Column{ {Name: "adhoc_plan_id", Type: field.TypeUUID}, @@ -1358,6 +1400,7 @@ var ( TeamsTable, TokensTable, UsersTable, + ValidationsTable, AdhocPlanNextAdhocPlanTable, CompetitionCompetitionToDNSTable, EnvironmentEnvironmentToUserTable, @@ -1423,6 +1466,7 @@ func init() { ProvisioningStepsTable.ForeignKeys[7].RefTable = FileDownloadsTable ProvisioningStepsTable.ForeignKeys[8].RefTable = FileExtractsTable ScriptsTable.ForeignKeys[0].RefTable = EnvironmentsTable + ScriptsTable.ForeignKeys[1].RefTable = ValidationsTable ServerTasksTable.ForeignKeys[0].RefTable = AuthUsersTable ServerTasksTable.ForeignKeys[1].RefTable = EnvironmentsTable ServerTasksTable.ForeignKeys[2].RefTable = BuildsTable @@ -1443,6 +1487,7 @@ func init() { UsersTable.ForeignKeys[1].RefTable = FindingsTable UsersTable.ForeignKeys[2].RefTable = HostsTable UsersTable.ForeignKeys[3].RefTable = ScriptsTable + ValidationsTable.ForeignKeys[0].RefTable = AgentTasksTable AdhocPlanNextAdhocPlanTable.ForeignKeys[0].RefTable = AdhocPlansTable AdhocPlanNextAdhocPlanTable.ForeignKeys[1].RefTable = AdhocPlansTable CompetitionCompetitionToDNSTable.ForeignKeys[0].RefTable = CompetitionsTable diff --git a/ent/mutation.go b/ent/mutation.go index 75c398ec..a1f8b3b9 100755 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -44,6 +44,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" "entgo.io/ent" @@ -93,6 +94,7 @@ const ( TypeTeam = "Team" TypeToken = "Token" TypeUser = "User" + TypeValidation = "Validation" ) // AdhocPlanMutation represents an operation that mutates the AdhocPlan nodes in the graph. @@ -2225,6 +2227,8 @@ type AgentTaskMutation struct { _AgentTaskToAdhocPlan map[uuid.UUID]struct{} removed_AgentTaskToAdhocPlan map[uuid.UUID]struct{} cleared_AgentTaskToAdhocPlan bool + _AgentTaskToValidation *uuid.UUID + cleared_AgentTaskToValidation bool done bool oldValue func(context.Context) (*AgentTask, error) predicates []predicate.AgentTask @@ -2683,6 +2687,45 @@ func (m *AgentTaskMutation) ResetAgentTaskToAdhocPlan() { m.removed_AgentTaskToAdhocPlan = nil } +// SetAgentTaskToValidationID sets the "AgentTaskToValidation" edge to the Validation entity by id. +func (m *AgentTaskMutation) SetAgentTaskToValidationID(id uuid.UUID) { + m._AgentTaskToValidation = &id +} + +// ClearAgentTaskToValidation clears the "AgentTaskToValidation" edge to the Validation entity. +func (m *AgentTaskMutation) ClearAgentTaskToValidation() { + m.cleared_AgentTaskToValidation = true +} + +// AgentTaskToValidationCleared reports if the "AgentTaskToValidation" edge to the Validation entity was cleared. +func (m *AgentTaskMutation) AgentTaskToValidationCleared() bool { + return m.cleared_AgentTaskToValidation +} + +// AgentTaskToValidationID returns the "AgentTaskToValidation" edge ID in the mutation. +func (m *AgentTaskMutation) AgentTaskToValidationID() (id uuid.UUID, exists bool) { + if m._AgentTaskToValidation != nil { + return *m._AgentTaskToValidation, true + } + return +} + +// AgentTaskToValidationIDs returns the "AgentTaskToValidation" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// AgentTaskToValidationID instead. It exists only for internal usage by the builders. +func (m *AgentTaskMutation) AgentTaskToValidationIDs() (ids []uuid.UUID) { + if id := m._AgentTaskToValidation; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetAgentTaskToValidation resets all changes to the "AgentTaskToValidation" edge. +func (m *AgentTaskMutation) ResetAgentTaskToValidation() { + m._AgentTaskToValidation = nil + m.cleared_AgentTaskToValidation = false +} + // Where appends a list predicates to the AgentTaskMutation builder. func (m *AgentTaskMutation) Where(ps ...predicate.AgentTask) { m.predicates = append(m.predicates, ps...) @@ -2901,7 +2944,7 @@ func (m *AgentTaskMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *AgentTaskMutation) AddedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m._AgentTaskToProvisioningStep != nil { edges = append(edges, agenttask.EdgeAgentTaskToProvisioningStep) } @@ -2911,6 +2954,9 @@ func (m *AgentTaskMutation) AddedEdges() []string { if m._AgentTaskToAdhocPlan != nil { edges = append(edges, agenttask.EdgeAgentTaskToAdhocPlan) } + if m._AgentTaskToValidation != nil { + edges = append(edges, agenttask.EdgeAgentTaskToValidation) + } return edges } @@ -2932,13 +2978,17 @@ func (m *AgentTaskMutation) AddedIDs(name string) []ent.Value { ids = append(ids, id) } return ids + case agenttask.EdgeAgentTaskToValidation: + if id := m._AgentTaskToValidation; id != nil { + return []ent.Value{*id} + } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *AgentTaskMutation) RemovedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.removed_AgentTaskToAdhocPlan != nil { edges = append(edges, agenttask.EdgeAgentTaskToAdhocPlan) } @@ -2961,7 +3011,7 @@ func (m *AgentTaskMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *AgentTaskMutation) ClearedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.cleared_AgentTaskToProvisioningStep { edges = append(edges, agenttask.EdgeAgentTaskToProvisioningStep) } @@ -2971,6 +3021,9 @@ func (m *AgentTaskMutation) ClearedEdges() []string { if m.cleared_AgentTaskToAdhocPlan { edges = append(edges, agenttask.EdgeAgentTaskToAdhocPlan) } + if m.cleared_AgentTaskToValidation { + edges = append(edges, agenttask.EdgeAgentTaskToValidation) + } return edges } @@ -2984,6 +3037,8 @@ func (m *AgentTaskMutation) EdgeCleared(name string) bool { return m.cleared_AgentTaskToProvisionedHost case agenttask.EdgeAgentTaskToAdhocPlan: return m.cleared_AgentTaskToAdhocPlan + case agenttask.EdgeAgentTaskToValidation: + return m.cleared_AgentTaskToValidation } return false } @@ -2998,6 +3053,9 @@ func (m *AgentTaskMutation) ClearEdge(name string) error { case agenttask.EdgeAgentTaskToProvisionedHost: m.ClearAgentTaskToProvisionedHost() return nil + case agenttask.EdgeAgentTaskToValidation: + m.ClearAgentTaskToValidation() + return nil } return fmt.Errorf("unknown AgentTask unique edge %s", name) } @@ -3015,6 +3073,9 @@ func (m *AgentTaskMutation) ResetEdge(name string) error { case agenttask.EdgeAgentTaskToAdhocPlan: m.ResetAgentTaskToAdhocPlan() return nil + case agenttask.EdgeAgentTaskToValidation: + m.ResetAgentTaskToValidation() + return nil } return fmt.Errorf("unknown AgentTask edge %s", name) } @@ -24420,6 +24481,8 @@ type ScriptMutation struct { cleared_ScriptToFinding bool _ScriptToEnvironment *uuid.UUID cleared_ScriptToEnvironment bool + _ScriptToValidation *uuid.UUID + cleared_ScriptToValidation bool done bool oldValue func(context.Context) (*Script, error) predicates []predicate.Script @@ -25201,6 +25264,45 @@ func (m *ScriptMutation) ResetScriptToEnvironment() { m.cleared_ScriptToEnvironment = false } +// SetScriptToValidationID sets the "ScriptToValidation" edge to the Validation entity by id. +func (m *ScriptMutation) SetScriptToValidationID(id uuid.UUID) { + m._ScriptToValidation = &id +} + +// ClearScriptToValidation clears the "ScriptToValidation" edge to the Validation entity. +func (m *ScriptMutation) ClearScriptToValidation() { + m.cleared_ScriptToValidation = true +} + +// ScriptToValidationCleared reports if the "ScriptToValidation" edge to the Validation entity was cleared. +func (m *ScriptMutation) ScriptToValidationCleared() bool { + return m.cleared_ScriptToValidation +} + +// ScriptToValidationID returns the "ScriptToValidation" edge ID in the mutation. +func (m *ScriptMutation) ScriptToValidationID() (id uuid.UUID, exists bool) { + if m._ScriptToValidation != nil { + return *m._ScriptToValidation, true + } + return +} + +// ScriptToValidationIDs returns the "ScriptToValidation" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// ScriptToValidationID instead. It exists only for internal usage by the builders. +func (m *ScriptMutation) ScriptToValidationIDs() (ids []uuid.UUID) { + if id := m._ScriptToValidation; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetScriptToValidation resets all changes to the "ScriptToValidation" edge. +func (m *ScriptMutation) ResetScriptToValidation() { + m._ScriptToValidation = nil + m.cleared_ScriptToValidation = false +} + // Where appends a list predicates to the ScriptMutation builder. func (m *ScriptMutation) Where(ps ...predicate.Script) { m.predicates = append(m.predicates, ps...) @@ -25567,7 +25669,7 @@ func (m *ScriptMutation) ResetField(name string) error { // AddedEdges returns all edge names that were set/added in this mutation. func (m *ScriptMutation) AddedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m._ScriptToUser != nil { edges = append(edges, script.EdgeScriptToUser) } @@ -25577,6 +25679,9 @@ func (m *ScriptMutation) AddedEdges() []string { if m._ScriptToEnvironment != nil { edges = append(edges, script.EdgeScriptToEnvironment) } + if m._ScriptToValidation != nil { + edges = append(edges, script.EdgeScriptToValidation) + } return edges } @@ -25600,13 +25705,17 @@ func (m *ScriptMutation) AddedIDs(name string) []ent.Value { if id := m._ScriptToEnvironment; id != nil { return []ent.Value{*id} } + case script.EdgeScriptToValidation: + if id := m._ScriptToValidation; id != nil { + return []ent.Value{*id} + } } return nil } // RemovedEdges returns all edge names that were removed in this mutation. func (m *ScriptMutation) RemovedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.removed_ScriptToUser != nil { edges = append(edges, script.EdgeScriptToUser) } @@ -25638,7 +25747,7 @@ func (m *ScriptMutation) RemovedIDs(name string) []ent.Value { // ClearedEdges returns all edge names that were cleared in this mutation. func (m *ScriptMutation) ClearedEdges() []string { - edges := make([]string, 0, 3) + edges := make([]string, 0, 4) if m.cleared_ScriptToUser { edges = append(edges, script.EdgeScriptToUser) } @@ -25648,6 +25757,9 @@ func (m *ScriptMutation) ClearedEdges() []string { if m.cleared_ScriptToEnvironment { edges = append(edges, script.EdgeScriptToEnvironment) } + if m.cleared_ScriptToValidation { + edges = append(edges, script.EdgeScriptToValidation) + } return edges } @@ -25661,6 +25773,8 @@ func (m *ScriptMutation) EdgeCleared(name string) bool { return m.cleared_ScriptToFinding case script.EdgeScriptToEnvironment: return m.cleared_ScriptToEnvironment + case script.EdgeScriptToValidation: + return m.cleared_ScriptToValidation } return false } @@ -25672,6 +25786,9 @@ func (m *ScriptMutation) ClearEdge(name string) error { case script.EdgeScriptToEnvironment: m.ClearScriptToEnvironment() return nil + case script.EdgeScriptToValidation: + m.ClearScriptToValidation() + return nil } return fmt.Errorf("unknown Script unique edge %s", name) } @@ -25689,6 +25806,9 @@ func (m *ScriptMutation) ResetEdge(name string) error { case script.EdgeScriptToEnvironment: m.ResetScriptToEnvironment() return nil + case script.EdgeScriptToValidation: + m.ResetScriptToValidation() + return nil } return fmt.Errorf("unknown Script edge %s", name) } @@ -29935,3 +30055,1299 @@ func (m *UserMutation) ResetEdge(name string) error { } return fmt.Errorf("unknown User edge %s", name) } + +// ValidationMutation represents an operation that mutates the Validation nodes in the graph. +type ValidationMutation struct { + config + op Op + typ string + id *uuid.UUID + hcl_id *string + validation_type *string + output *string + state *validation.State + error_message *string + regex *string + ip *string + port *int + addport *int + hostname *string + nameservers *[]string + package_name *string + username *string + group_name *string + field_path *string + service_name *string + process_name *string + clearedFields map[string]struct{} + _ValidationToAgentTask *uuid.UUID + cleared_ValidationToAgentTask bool + _ValidationToScript map[uuid.UUID]struct{} + removed_ValidationToScript map[uuid.UUID]struct{} + cleared_ValidationToScript bool + done bool + oldValue func(context.Context) (*Validation, error) + predicates []predicate.Validation +} + +var _ ent.Mutation = (*ValidationMutation)(nil) + +// validationOption allows management of the mutation configuration using functional options. +type validationOption func(*ValidationMutation) + +// newValidationMutation creates new mutation for the Validation entity. +func newValidationMutation(c config, op Op, opts ...validationOption) *ValidationMutation { + m := &ValidationMutation{ + config: c, + op: op, + typ: TypeValidation, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withValidationID sets the ID field of the mutation. +func withValidationID(id uuid.UUID) validationOption { + return func(m *ValidationMutation) { + var ( + err error + once sync.Once + value *Validation + ) + m.oldValue = func(ctx context.Context) (*Validation, error) { + once.Do(func() { + if m.done { + err = fmt.Errorf("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Validation.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withValidation sets the old Validation of the mutation. +func withValidation(node *Validation) validationOption { + return func(m *ValidationMutation) { + m.oldValue = func(context.Context) (*Validation, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ValidationMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ValidationMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, fmt.Errorf("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Validation entities. +func (m *ValidationMutation) SetID(id uuid.UUID) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ValidationMutation) ID() (id uuid.UUID, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// SetHclID sets the "hcl_id" field. +func (m *ValidationMutation) SetHclID(s string) { + m.hcl_id = &s +} + +// HclID returns the value of the "hcl_id" field in the mutation. +func (m *ValidationMutation) HclID() (r string, exists bool) { + v := m.hcl_id + if v == nil { + return + } + return *v, true +} + +// OldHclID returns the old "hcl_id" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldHclID(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldHclID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldHclID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldHclID: %w", err) + } + return oldValue.HclID, nil +} + +// ResetHclID resets all changes to the "hcl_id" field. +func (m *ValidationMutation) ResetHclID() { + m.hcl_id = nil +} + +// SetValidationType sets the "validation_type" field. +func (m *ValidationMutation) SetValidationType(s string) { + m.validation_type = &s +} + +// ValidationType returns the value of the "validation_type" field in the mutation. +func (m *ValidationMutation) ValidationType() (r string, exists bool) { + v := m.validation_type + if v == nil { + return + } + return *v, true +} + +// OldValidationType returns the old "validation_type" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldValidationType(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldValidationType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldValidationType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldValidationType: %w", err) + } + return oldValue.ValidationType, nil +} + +// ResetValidationType resets all changes to the "validation_type" field. +func (m *ValidationMutation) ResetValidationType() { + m.validation_type = nil +} + +// SetOutput sets the "output" field. +func (m *ValidationMutation) SetOutput(s string) { + m.output = &s +} + +// Output returns the value of the "output" field in the mutation. +func (m *ValidationMutation) Output() (r string, exists bool) { + v := m.output + if v == nil { + return + } + return *v, true +} + +// OldOutput returns the old "output" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldOutput(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldOutput is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldOutput requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldOutput: %w", err) + } + return oldValue.Output, nil +} + +// ResetOutput resets all changes to the "output" field. +func (m *ValidationMutation) ResetOutput() { + m.output = nil +} + +// SetState sets the "state" field. +func (m *ValidationMutation) SetState(v validation.State) { + m.state = &v +} + +// State returns the value of the "state" field in the mutation. +func (m *ValidationMutation) State() (r validation.State, exists bool) { + v := m.state + if v == nil { + return + } + return *v, true +} + +// OldState returns the old "state" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldState(ctx context.Context) (v validation.State, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldState is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldState requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldState: %w", err) + } + return oldValue.State, nil +} + +// ResetState resets all changes to the "state" field. +func (m *ValidationMutation) ResetState() { + m.state = nil +} + +// SetErrorMessage sets the "error_message" field. +func (m *ValidationMutation) SetErrorMessage(s string) { + m.error_message = &s +} + +// ErrorMessage returns the value of the "error_message" field in the mutation. +func (m *ValidationMutation) ErrorMessage() (r string, exists bool) { + v := m.error_message + if v == nil { + return + } + return *v, true +} + +// OldErrorMessage returns the old "error_message" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldErrorMessage(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldErrorMessage is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldErrorMessage requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldErrorMessage: %w", err) + } + return oldValue.ErrorMessage, nil +} + +// ResetErrorMessage resets all changes to the "error_message" field. +func (m *ValidationMutation) ResetErrorMessage() { + m.error_message = nil +} + +// SetRegex sets the "regex" field. +func (m *ValidationMutation) SetRegex(s string) { + m.regex = &s +} + +// Regex returns the value of the "regex" field in the mutation. +func (m *ValidationMutation) Regex() (r string, exists bool) { + v := m.regex + if v == nil { + return + } + return *v, true +} + +// OldRegex returns the old "regex" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldRegex(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldRegex is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldRegex requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRegex: %w", err) + } + return oldValue.Regex, nil +} + +// ResetRegex resets all changes to the "regex" field. +func (m *ValidationMutation) ResetRegex() { + m.regex = nil +} + +// SetIP sets the "ip" field. +func (m *ValidationMutation) SetIP(s string) { + m.ip = &s +} + +// IP returns the value of the "ip" field in the mutation. +func (m *ValidationMutation) IP() (r string, exists bool) { + v := m.ip + if v == nil { + return + } + return *v, true +} + +// OldIP returns the old "ip" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldIP(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldIP is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldIP requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldIP: %w", err) + } + return oldValue.IP, nil +} + +// ResetIP resets all changes to the "ip" field. +func (m *ValidationMutation) ResetIP() { + m.ip = nil +} + +// SetPort sets the "port" field. +func (m *ValidationMutation) SetPort(i int) { + m.port = &i + m.addport = nil +} + +// Port returns the value of the "port" field in the mutation. +func (m *ValidationMutation) Port() (r int, exists bool) { + v := m.port + if v == nil { + return + } + return *v, true +} + +// OldPort returns the old "port" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldPort(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldPort is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldPort requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPort: %w", err) + } + return oldValue.Port, nil +} + +// AddPort adds i to the "port" field. +func (m *ValidationMutation) AddPort(i int) { + if m.addport != nil { + *m.addport += i + } else { + m.addport = &i + } +} + +// AddedPort returns the value that was added to the "port" field in this mutation. +func (m *ValidationMutation) AddedPort() (r int, exists bool) { + v := m.addport + if v == nil { + return + } + return *v, true +} + +// ResetPort resets all changes to the "port" field. +func (m *ValidationMutation) ResetPort() { + m.port = nil + m.addport = nil +} + +// SetHostname sets the "hostname" field. +func (m *ValidationMutation) SetHostname(s string) { + m.hostname = &s +} + +// Hostname returns the value of the "hostname" field in the mutation. +func (m *ValidationMutation) Hostname() (r string, exists bool) { + v := m.hostname + if v == nil { + return + } + return *v, true +} + +// OldHostname returns the old "hostname" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldHostname(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldHostname is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldHostname requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldHostname: %w", err) + } + return oldValue.Hostname, nil +} + +// ResetHostname resets all changes to the "hostname" field. +func (m *ValidationMutation) ResetHostname() { + m.hostname = nil +} + +// SetNameservers sets the "nameservers" field. +func (m *ValidationMutation) SetNameservers(s []string) { + m.nameservers = &s +} + +// Nameservers returns the value of the "nameservers" field in the mutation. +func (m *ValidationMutation) Nameservers() (r []string, exists bool) { + v := m.nameservers + if v == nil { + return + } + return *v, true +} + +// OldNameservers returns the old "nameservers" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldNameservers(ctx context.Context) (v []string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldNameservers is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldNameservers requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldNameservers: %w", err) + } + return oldValue.Nameservers, nil +} + +// ResetNameservers resets all changes to the "nameservers" field. +func (m *ValidationMutation) ResetNameservers() { + m.nameservers = nil +} + +// SetPackageName sets the "package_name" field. +func (m *ValidationMutation) SetPackageName(s string) { + m.package_name = &s +} + +// PackageName returns the value of the "package_name" field in the mutation. +func (m *ValidationMutation) PackageName() (r string, exists bool) { + v := m.package_name + if v == nil { + return + } + return *v, true +} + +// OldPackageName returns the old "package_name" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldPackageName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldPackageName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldPackageName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldPackageName: %w", err) + } + return oldValue.PackageName, nil +} + +// ResetPackageName resets all changes to the "package_name" field. +func (m *ValidationMutation) ResetPackageName() { + m.package_name = nil +} + +// SetUsername sets the "username" field. +func (m *ValidationMutation) SetUsername(s string) { + m.username = &s +} + +// Username returns the value of the "username" field in the mutation. +func (m *ValidationMutation) Username() (r string, exists bool) { + v := m.username + if v == nil { + return + } + return *v, true +} + +// OldUsername returns the old "username" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldUsername(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldUsername is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldUsername requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUsername: %w", err) + } + return oldValue.Username, nil +} + +// ResetUsername resets all changes to the "username" field. +func (m *ValidationMutation) ResetUsername() { + m.username = nil +} + +// SetGroupName sets the "group_name" field. +func (m *ValidationMutation) SetGroupName(s string) { + m.group_name = &s +} + +// GroupName returns the value of the "group_name" field in the mutation. +func (m *ValidationMutation) GroupName() (r string, exists bool) { + v := m.group_name + if v == nil { + return + } + return *v, true +} + +// OldGroupName returns the old "group_name" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldGroupName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldGroupName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldGroupName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldGroupName: %w", err) + } + return oldValue.GroupName, nil +} + +// ResetGroupName resets all changes to the "group_name" field. +func (m *ValidationMutation) ResetGroupName() { + m.group_name = nil +} + +// SetFieldPath sets the "field_path" field. +func (m *ValidationMutation) SetFieldPath(s string) { + m.field_path = &s +} + +// FieldPath returns the value of the "field_path" field in the mutation. +func (m *ValidationMutation) FieldPath() (r string, exists bool) { + v := m.field_path + if v == nil { + return + } + return *v, true +} + +// OldFieldPath returns the old "field_path" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldFieldPath(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldFieldPath is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldFieldPath requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldFieldPath: %w", err) + } + return oldValue.FieldPath, nil +} + +// ResetFieldPath resets all changes to the "field_path" field. +func (m *ValidationMutation) ResetFieldPath() { + m.field_path = nil +} + +// SetServiceName sets the "service_name" field. +func (m *ValidationMutation) SetServiceName(s string) { + m.service_name = &s +} + +// ServiceName returns the value of the "service_name" field in the mutation. +func (m *ValidationMutation) ServiceName() (r string, exists bool) { + v := m.service_name + if v == nil { + return + } + return *v, true +} + +// OldServiceName returns the old "service_name" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldServiceName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldServiceName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldServiceName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldServiceName: %w", err) + } + return oldValue.ServiceName, nil +} + +// ResetServiceName resets all changes to the "service_name" field. +func (m *ValidationMutation) ResetServiceName() { + m.service_name = nil +} + +// SetProcessName sets the "process_name" field. +func (m *ValidationMutation) SetProcessName(s string) { + m.process_name = &s +} + +// ProcessName returns the value of the "process_name" field in the mutation. +func (m *ValidationMutation) ProcessName() (r string, exists bool) { + v := m.process_name + if v == nil { + return + } + return *v, true +} + +// OldProcessName returns the old "process_name" field's value of the Validation entity. +// If the Validation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *ValidationMutation) OldProcessName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldProcessName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldProcessName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldProcessName: %w", err) + } + return oldValue.ProcessName, nil +} + +// ResetProcessName resets all changes to the "process_name" field. +func (m *ValidationMutation) ResetProcessName() { + m.process_name = nil +} + +// SetValidationToAgentTaskID sets the "ValidationToAgentTask" edge to the AgentTask entity by id. +func (m *ValidationMutation) SetValidationToAgentTaskID(id uuid.UUID) { + m._ValidationToAgentTask = &id +} + +// ClearValidationToAgentTask clears the "ValidationToAgentTask" edge to the AgentTask entity. +func (m *ValidationMutation) ClearValidationToAgentTask() { + m.cleared_ValidationToAgentTask = true +} + +// ValidationToAgentTaskCleared reports if the "ValidationToAgentTask" edge to the AgentTask entity was cleared. +func (m *ValidationMutation) ValidationToAgentTaskCleared() bool { + return m.cleared_ValidationToAgentTask +} + +// ValidationToAgentTaskID returns the "ValidationToAgentTask" edge ID in the mutation. +func (m *ValidationMutation) ValidationToAgentTaskID() (id uuid.UUID, exists bool) { + if m._ValidationToAgentTask != nil { + return *m._ValidationToAgentTask, true + } + return +} + +// ValidationToAgentTaskIDs returns the "ValidationToAgentTask" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// ValidationToAgentTaskID instead. It exists only for internal usage by the builders. +func (m *ValidationMutation) ValidationToAgentTaskIDs() (ids []uuid.UUID) { + if id := m._ValidationToAgentTask; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetValidationToAgentTask resets all changes to the "ValidationToAgentTask" edge. +func (m *ValidationMutation) ResetValidationToAgentTask() { + m._ValidationToAgentTask = nil + m.cleared_ValidationToAgentTask = false +} + +// AddValidationToScriptIDs adds the "ValidationToScript" edge to the Script entity by ids. +func (m *ValidationMutation) AddValidationToScriptIDs(ids ...uuid.UUID) { + if m._ValidationToScript == nil { + m._ValidationToScript = make(map[uuid.UUID]struct{}) + } + for i := range ids { + m._ValidationToScript[ids[i]] = struct{}{} + } +} + +// ClearValidationToScript clears the "ValidationToScript" edge to the Script entity. +func (m *ValidationMutation) ClearValidationToScript() { + m.cleared_ValidationToScript = true +} + +// ValidationToScriptCleared reports if the "ValidationToScript" edge to the Script entity was cleared. +func (m *ValidationMutation) ValidationToScriptCleared() bool { + return m.cleared_ValidationToScript +} + +// RemoveValidationToScriptIDs removes the "ValidationToScript" edge to the Script entity by IDs. +func (m *ValidationMutation) RemoveValidationToScriptIDs(ids ...uuid.UUID) { + if m.removed_ValidationToScript == nil { + m.removed_ValidationToScript = make(map[uuid.UUID]struct{}) + } + for i := range ids { + delete(m._ValidationToScript, ids[i]) + m.removed_ValidationToScript[ids[i]] = struct{}{} + } +} + +// RemovedValidationToScript returns the removed IDs of the "ValidationToScript" edge to the Script entity. +func (m *ValidationMutation) RemovedValidationToScriptIDs() (ids []uuid.UUID) { + for id := range m.removed_ValidationToScript { + ids = append(ids, id) + } + return +} + +// ValidationToScriptIDs returns the "ValidationToScript" edge IDs in the mutation. +func (m *ValidationMutation) ValidationToScriptIDs() (ids []uuid.UUID) { + for id := range m._ValidationToScript { + ids = append(ids, id) + } + return +} + +// ResetValidationToScript resets all changes to the "ValidationToScript" edge. +func (m *ValidationMutation) ResetValidationToScript() { + m._ValidationToScript = nil + m.cleared_ValidationToScript = false + m.removed_ValidationToScript = nil +} + +// Where appends a list predicates to the ValidationMutation builder. +func (m *ValidationMutation) Where(ps ...predicate.Validation) { + m.predicates = append(m.predicates, ps...) +} + +// Op returns the operation name. +func (m *ValidationMutation) Op() Op { + return m.op +} + +// Type returns the node type of this mutation (Validation). +func (m *ValidationMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ValidationMutation) Fields() []string { + fields := make([]string, 0, 16) + if m.hcl_id != nil { + fields = append(fields, validation.FieldHclID) + } + if m.validation_type != nil { + fields = append(fields, validation.FieldValidationType) + } + if m.output != nil { + fields = append(fields, validation.FieldOutput) + } + if m.state != nil { + fields = append(fields, validation.FieldState) + } + if m.error_message != nil { + fields = append(fields, validation.FieldErrorMessage) + } + if m.regex != nil { + fields = append(fields, validation.FieldRegex) + } + if m.ip != nil { + fields = append(fields, validation.FieldIP) + } + if m.port != nil { + fields = append(fields, validation.FieldPort) + } + if m.hostname != nil { + fields = append(fields, validation.FieldHostname) + } + if m.nameservers != nil { + fields = append(fields, validation.FieldNameservers) + } + if m.package_name != nil { + fields = append(fields, validation.FieldPackageName) + } + if m.username != nil { + fields = append(fields, validation.FieldUsername) + } + if m.group_name != nil { + fields = append(fields, validation.FieldGroupName) + } + if m.field_path != nil { + fields = append(fields, validation.FieldFieldPath) + } + if m.service_name != nil { + fields = append(fields, validation.FieldServiceName) + } + if m.process_name != nil { + fields = append(fields, validation.FieldProcessName) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ValidationMutation) Field(name string) (ent.Value, bool) { + switch name { + case validation.FieldHclID: + return m.HclID() + case validation.FieldValidationType: + return m.ValidationType() + case validation.FieldOutput: + return m.Output() + case validation.FieldState: + return m.State() + case validation.FieldErrorMessage: + return m.ErrorMessage() + case validation.FieldRegex: + return m.Regex() + case validation.FieldIP: + return m.IP() + case validation.FieldPort: + return m.Port() + case validation.FieldHostname: + return m.Hostname() + case validation.FieldNameservers: + return m.Nameservers() + case validation.FieldPackageName: + return m.PackageName() + case validation.FieldUsername: + return m.Username() + case validation.FieldGroupName: + return m.GroupName() + case validation.FieldFieldPath: + return m.FieldPath() + case validation.FieldServiceName: + return m.ServiceName() + case validation.FieldProcessName: + return m.ProcessName() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ValidationMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case validation.FieldHclID: + return m.OldHclID(ctx) + case validation.FieldValidationType: + return m.OldValidationType(ctx) + case validation.FieldOutput: + return m.OldOutput(ctx) + case validation.FieldState: + return m.OldState(ctx) + case validation.FieldErrorMessage: + return m.OldErrorMessage(ctx) + case validation.FieldRegex: + return m.OldRegex(ctx) + case validation.FieldIP: + return m.OldIP(ctx) + case validation.FieldPort: + return m.OldPort(ctx) + case validation.FieldHostname: + return m.OldHostname(ctx) + case validation.FieldNameservers: + return m.OldNameservers(ctx) + case validation.FieldPackageName: + return m.OldPackageName(ctx) + case validation.FieldUsername: + return m.OldUsername(ctx) + case validation.FieldGroupName: + return m.OldGroupName(ctx) + case validation.FieldFieldPath: + return m.OldFieldPath(ctx) + case validation.FieldServiceName: + return m.OldServiceName(ctx) + case validation.FieldProcessName: + return m.OldProcessName(ctx) + } + return nil, fmt.Errorf("unknown Validation field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ValidationMutation) SetField(name string, value ent.Value) error { + switch name { + case validation.FieldHclID: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetHclID(v) + return nil + case validation.FieldValidationType: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetValidationType(v) + return nil + case validation.FieldOutput: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetOutput(v) + return nil + case validation.FieldState: + v, ok := value.(validation.State) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetState(v) + return nil + case validation.FieldErrorMessage: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetErrorMessage(v) + return nil + case validation.FieldRegex: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRegex(v) + return nil + case validation.FieldIP: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetIP(v) + return nil + case validation.FieldPort: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPort(v) + return nil + case validation.FieldHostname: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetHostname(v) + return nil + case validation.FieldNameservers: + v, ok := value.([]string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetNameservers(v) + return nil + case validation.FieldPackageName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetPackageName(v) + return nil + case validation.FieldUsername: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUsername(v) + return nil + case validation.FieldGroupName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGroupName(v) + return nil + case validation.FieldFieldPath: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetFieldPath(v) + return nil + case validation.FieldServiceName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetServiceName(v) + return nil + case validation.FieldProcessName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetProcessName(v) + return nil + } + return fmt.Errorf("unknown Validation field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ValidationMutation) AddedFields() []string { + var fields []string + if m.addport != nil { + fields = append(fields, validation.FieldPort) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ValidationMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case validation.FieldPort: + return m.AddedPort() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ValidationMutation) AddField(name string, value ent.Value) error { + switch name { + case validation.FieldPort: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddPort(v) + return nil + } + return fmt.Errorf("unknown Validation numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ValidationMutation) ClearedFields() []string { + return nil +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ValidationMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ValidationMutation) ClearField(name string) error { + return fmt.Errorf("unknown Validation nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ValidationMutation) ResetField(name string) error { + switch name { + case validation.FieldHclID: + m.ResetHclID() + return nil + case validation.FieldValidationType: + m.ResetValidationType() + return nil + case validation.FieldOutput: + m.ResetOutput() + return nil + case validation.FieldState: + m.ResetState() + return nil + case validation.FieldErrorMessage: + m.ResetErrorMessage() + return nil + case validation.FieldRegex: + m.ResetRegex() + return nil + case validation.FieldIP: + m.ResetIP() + return nil + case validation.FieldPort: + m.ResetPort() + return nil + case validation.FieldHostname: + m.ResetHostname() + return nil + case validation.FieldNameservers: + m.ResetNameservers() + return nil + case validation.FieldPackageName: + m.ResetPackageName() + return nil + case validation.FieldUsername: + m.ResetUsername() + return nil + case validation.FieldGroupName: + m.ResetGroupName() + return nil + case validation.FieldFieldPath: + m.ResetFieldPath() + return nil + case validation.FieldServiceName: + m.ResetServiceName() + return nil + case validation.FieldProcessName: + m.ResetProcessName() + return nil + } + return fmt.Errorf("unknown Validation field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ValidationMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m._ValidationToAgentTask != nil { + edges = append(edges, validation.EdgeValidationToAgentTask) + } + if m._ValidationToScript != nil { + edges = append(edges, validation.EdgeValidationToScript) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ValidationMutation) AddedIDs(name string) []ent.Value { + switch name { + case validation.EdgeValidationToAgentTask: + if id := m._ValidationToAgentTask; id != nil { + return []ent.Value{*id} + } + case validation.EdgeValidationToScript: + ids := make([]ent.Value, 0, len(m._ValidationToScript)) + for id := range m._ValidationToScript { + ids = append(ids, id) + } + return ids + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ValidationMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + if m.removed_ValidationToScript != nil { + edges = append(edges, validation.EdgeValidationToScript) + } + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ValidationMutation) RemovedIDs(name string) []ent.Value { + switch name { + case validation.EdgeValidationToScript: + ids := make([]ent.Value, 0, len(m.removed_ValidationToScript)) + for id := range m.removed_ValidationToScript { + ids = append(ids, id) + } + return ids + } + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ValidationMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.cleared_ValidationToAgentTask { + edges = append(edges, validation.EdgeValidationToAgentTask) + } + if m.cleared_ValidationToScript { + edges = append(edges, validation.EdgeValidationToScript) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ValidationMutation) EdgeCleared(name string) bool { + switch name { + case validation.EdgeValidationToAgentTask: + return m.cleared_ValidationToAgentTask + case validation.EdgeValidationToScript: + return m.cleared_ValidationToScript + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ValidationMutation) ClearEdge(name string) error { + switch name { + case validation.EdgeValidationToAgentTask: + m.ClearValidationToAgentTask() + return nil + } + return fmt.Errorf("unknown Validation unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ValidationMutation) ResetEdge(name string) error { + switch name { + case validation.EdgeValidationToAgentTask: + m.ResetValidationToAgentTask() + return nil + case validation.EdgeValidationToScript: + m.ResetValidationToScript() + return nil + } + return fmt.Errorf("unknown Validation edge %s", name) +} diff --git a/ent/node.go b/ent/node.go index abbed233..2030a487 100755 --- a/ent/node.go +++ b/ent/node.go @@ -44,6 +44,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" "github.com/hashicorp/go-multierror" ) @@ -293,7 +294,7 @@ func (at *AgentTask) Node(ctx context.Context) (node *Node, err error) { ID: at.ID, Type: "AgentTask", Fields: make([]*Field, 6), - Edges: make([]*Edge, 3), + Edges: make([]*Edge, 4), } var buf []byte if buf, err = json.Marshal(at.Command); err != nil { @@ -374,6 +375,16 @@ func (at *AgentTask) Node(ctx context.Context) (node *Node, err error) { if err != nil { return nil, err } + node.Edges[3] = &Edge{ + Type: "Validation", + Name: "AgentTaskToValidation", + } + err = at.QueryAgentTaskToValidation(). + Select(validation.FieldID). + Scan(ctx, &node.Edges[3].IDs) + if err != nil { + return nil, err + } return node, nil } @@ -2771,7 +2782,7 @@ func (s *Script) Node(ctx context.Context) (node *Node, err error) { ID: s.ID, Type: "Script", Fields: make([]*Field, 14), - Edges: make([]*Edge, 3), + Edges: make([]*Edge, 4), } var buf []byte if buf, err = json.Marshal(s.HclID); err != nil { @@ -2916,6 +2927,16 @@ func (s *Script) Node(ctx context.Context) (node *Node, err error) { if err != nil { return nil, err } + node.Edges[3] = &Edge{ + Type: "Validation", + Name: "ScriptToValidation", + } + err = s.QueryScriptToValidation(). + Select(validation.FieldID). + Scan(ctx, &node.Edges[3].IDs) + if err != nil { + return nil, err + } return node, nil } @@ -3369,6 +3390,165 @@ func (u *User) Node(ctx context.Context) (node *Node, err error) { return node, nil } +func (v *Validation) Node(ctx context.Context) (node *Node, err error) { + node = &Node{ + ID: v.ID, + Type: "Validation", + Fields: make([]*Field, 16), + Edges: make([]*Edge, 2), + } + var buf []byte + if buf, err = json.Marshal(v.HclID); err != nil { + return nil, err + } + node.Fields[0] = &Field{ + Type: "string", + Name: "hcl_id", + Value: string(buf), + } + if buf, err = json.Marshal(v.ValidationType); err != nil { + return nil, err + } + node.Fields[1] = &Field{ + Type: "string", + Name: "validation_type", + Value: string(buf), + } + if buf, err = json.Marshal(v.Output); err != nil { + return nil, err + } + node.Fields[2] = &Field{ + Type: "string", + Name: "output", + Value: string(buf), + } + if buf, err = json.Marshal(v.State); err != nil { + return nil, err + } + node.Fields[3] = &Field{ + Type: "validation.State", + Name: "state", + Value: string(buf), + } + if buf, err = json.Marshal(v.ErrorMessage); err != nil { + return nil, err + } + node.Fields[4] = &Field{ + Type: "string", + Name: "error_message", + Value: string(buf), + } + if buf, err = json.Marshal(v.Regex); err != nil { + return nil, err + } + node.Fields[5] = &Field{ + Type: "string", + Name: "regex", + Value: string(buf), + } + if buf, err = json.Marshal(v.IP); err != nil { + return nil, err + } + node.Fields[6] = &Field{ + Type: "string", + Name: "ip", + Value: string(buf), + } + if buf, err = json.Marshal(v.Port); err != nil { + return nil, err + } + node.Fields[7] = &Field{ + Type: "int", + Name: "port", + Value: string(buf), + } + if buf, err = json.Marshal(v.Hostname); err != nil { + return nil, err + } + node.Fields[8] = &Field{ + Type: "string", + Name: "hostname", + Value: string(buf), + } + if buf, err = json.Marshal(v.Nameservers); err != nil { + return nil, err + } + node.Fields[9] = &Field{ + Type: "[]string", + Name: "nameservers", + Value: string(buf), + } + if buf, err = json.Marshal(v.PackageName); err != nil { + return nil, err + } + node.Fields[10] = &Field{ + Type: "string", + Name: "package_name", + Value: string(buf), + } + if buf, err = json.Marshal(v.Username); err != nil { + return nil, err + } + node.Fields[11] = &Field{ + Type: "string", + Name: "username", + Value: string(buf), + } + if buf, err = json.Marshal(v.GroupName); err != nil { + return nil, err + } + node.Fields[12] = &Field{ + Type: "string", + Name: "group_name", + Value: string(buf), + } + if buf, err = json.Marshal(v.FieldPath); err != nil { + return nil, err + } + node.Fields[13] = &Field{ + Type: "string", + Name: "field_path", + Value: string(buf), + } + if buf, err = json.Marshal(v.ServiceName); err != nil { + return nil, err + } + node.Fields[14] = &Field{ + Type: "string", + Name: "service_name", + Value: string(buf), + } + if buf, err = json.Marshal(v.ProcessName); err != nil { + return nil, err + } + node.Fields[15] = &Field{ + Type: "string", + Name: "process_name", + Value: string(buf), + } + node.Edges[0] = &Edge{ + Type: "AgentTask", + Name: "ValidationToAgentTask", + } + err = v.QueryValidationToAgentTask(). + Select(agenttask.FieldID). + Scan(ctx, &node.Edges[0].IDs) + if err != nil { + return nil, err + } + node.Edges[1] = &Edge{ + Type: "Script", + Name: "ValidationToScript", + } + err = v.QueryValidationToScript(). + Select(script.FieldID). + Scan(ctx, &node.Edges[1].IDs) + if err != nil { + return nil, err + } + return node, nil +} + func (c *Client) Node(ctx context.Context, id uuid.UUID) (*Node, error) { n, err := c.Noder(ctx, id) if err != nil { @@ -3751,6 +3931,15 @@ func (c *Client) noder(ctx context.Context, table string, id uuid.UUID) (Noder, return nil, err } return n, nil + case validation.Table: + n, err := c.Validation.Query(). + Where(validation.ID(id)). + CollectFields(ctx, "Validation"). + Only(ctx) + if err != nil { + return nil, err + } + return n, nil default: return nil, fmt.Errorf("cannot resolve noder from table %q: %w", table, errNodeInvalidID) } @@ -4279,6 +4468,19 @@ func (c *Client) noders(ctx context.Context, table string, ids []uuid.UUID) ([]N *noder = node } } + case validation.Table: + nodes, err := c.Validation.Query(). + Where(validation.IDIn(ids...)). + CollectFields(ctx, "Validation"). + All(ctx) + if err != nil { + return nil, err + } + for _, node := range nodes { + for _, noder := range idmap[node.ID] { + *noder = node + } + } default: return nil, fmt.Errorf("cannot resolve noders from table %q: %w", table, errNodeInvalidID) } diff --git a/ent/pagination.go b/ent/pagination.go index 4d3d62e7..939ef25a 100755 --- a/ent/pagination.go +++ b/ent/pagination.go @@ -49,6 +49,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" "github.com/vektah/gqlparser/v2/gqlerror" "github.com/vmihailenco/msgpack/v5" @@ -8211,3 +8212,230 @@ func (u *User) ToEdge(order *UserOrder) *UserEdge { Cursor: order.Field.toCursor(u), } } + +// ValidationEdge is the edge representation of Validation. +type ValidationEdge struct { + Node *Validation `json:"node"` + Cursor Cursor `json:"cursor"` +} + +// ValidationConnection is the connection containing edges to Validation. +type ValidationConnection struct { + Edges []*ValidationEdge `json:"edges"` + PageInfo PageInfo `json:"pageInfo"` + TotalCount int `json:"totalCount"` +} + +// ValidationPaginateOption enables pagination customization. +type ValidationPaginateOption func(*validationPager) error + +// WithValidationOrder configures pagination ordering. +func WithValidationOrder(order *ValidationOrder) ValidationPaginateOption { + if order == nil { + order = DefaultValidationOrder + } + o := *order + return func(pager *validationPager) error { + if err := o.Direction.Validate(); err != nil { + return err + } + if o.Field == nil { + o.Field = DefaultValidationOrder.Field + } + pager.order = &o + return nil + } +} + +// WithValidationFilter configures pagination filter. +func WithValidationFilter(filter func(*ValidationQuery) (*ValidationQuery, error)) ValidationPaginateOption { + return func(pager *validationPager) error { + if filter == nil { + return errors.New("ValidationQuery filter cannot be nil") + } + pager.filter = filter + return nil + } +} + +type validationPager struct { + order *ValidationOrder + filter func(*ValidationQuery) (*ValidationQuery, error) +} + +func newValidationPager(opts []ValidationPaginateOption) (*validationPager, error) { + pager := &validationPager{} + for _, opt := range opts { + if err := opt(pager); err != nil { + return nil, err + } + } + if pager.order == nil { + pager.order = DefaultValidationOrder + } + return pager, nil +} + +func (p *validationPager) applyFilter(query *ValidationQuery) (*ValidationQuery, error) { + if p.filter != nil { + return p.filter(query) + } + return query, nil +} + +func (p *validationPager) toCursor(v *Validation) Cursor { + return p.order.Field.toCursor(v) +} + +func (p *validationPager) applyCursors(query *ValidationQuery, after, before *Cursor) *ValidationQuery { + for _, predicate := range cursorsToPredicates( + p.order.Direction, after, before, + p.order.Field.field, DefaultValidationOrder.Field.field, + ) { + query = query.Where(predicate) + } + return query +} + +func (p *validationPager) applyOrder(query *ValidationQuery, reverse bool) *ValidationQuery { + direction := p.order.Direction + if reverse { + direction = direction.reverse() + } + query = query.Order(direction.orderFunc(p.order.Field.field)) + if p.order.Field != DefaultValidationOrder.Field { + query = query.Order(direction.orderFunc(DefaultValidationOrder.Field.field)) + } + return query +} + +// Paginate executes the query and returns a relay based cursor connection to Validation. +func (v *ValidationQuery) Paginate( + ctx context.Context, after *Cursor, first *int, + before *Cursor, last *int, opts ...ValidationPaginateOption, +) (*ValidationConnection, error) { + if err := validateFirstLast(first, last); err != nil { + return nil, err + } + pager, err := newValidationPager(opts) + if err != nil { + return nil, err + } + + if v, err = pager.applyFilter(v); err != nil { + return nil, err + } + + conn := &ValidationConnection{Edges: []*ValidationEdge{}} + if !hasCollectedField(ctx, edgesField) || first != nil && *first == 0 || last != nil && *last == 0 { + if hasCollectedField(ctx, totalCountField) || + hasCollectedField(ctx, pageInfoField) { + count, err := v.Count(ctx) + if err != nil { + return nil, err + } + conn.TotalCount = count + conn.PageInfo.HasNextPage = first != nil && count > 0 + conn.PageInfo.HasPreviousPage = last != nil && count > 0 + } + return conn, nil + } + + if (after != nil || first != nil || before != nil || last != nil) && hasCollectedField(ctx, totalCountField) { + count, err := v.Clone().Count(ctx) + if err != nil { + return nil, err + } + conn.TotalCount = count + } + + v = pager.applyCursors(v, after, before) + v = pager.applyOrder(v, last != nil) + var limit int + if first != nil { + limit = *first + 1 + } else if last != nil { + limit = *last + 1 + } + if limit > 0 { + v = v.Limit(limit) + } + + if field := getCollectedField(ctx, edgesField, nodeField); field != nil { + v = v.collectField(graphql.GetOperationContext(ctx), *field) + } + + nodes, err := v.All(ctx) + if err != nil || len(nodes) == 0 { + return conn, err + } + + if len(nodes) == limit { + conn.PageInfo.HasNextPage = first != nil + conn.PageInfo.HasPreviousPage = last != nil + nodes = nodes[:len(nodes)-1] + } + + var nodeAt func(int) *Validation + if last != nil { + n := len(nodes) - 1 + nodeAt = func(i int) *Validation { + return nodes[n-i] + } + } else { + nodeAt = func(i int) *Validation { + return nodes[i] + } + } + + conn.Edges = make([]*ValidationEdge, len(nodes)) + for i := range nodes { + node := nodeAt(i) + conn.Edges[i] = &ValidationEdge{ + Node: node, + Cursor: pager.toCursor(node), + } + } + + conn.PageInfo.StartCursor = &conn.Edges[0].Cursor + conn.PageInfo.EndCursor = &conn.Edges[len(conn.Edges)-1].Cursor + if conn.TotalCount == 0 { + conn.TotalCount = len(nodes) + } + + return conn, nil +} + +// ValidationOrderField defines the ordering field of Validation. +type ValidationOrderField struct { + field string + toCursor func(*Validation) Cursor +} + +// ValidationOrder defines the ordering of Validation. +type ValidationOrder struct { + Direction OrderDirection `json:"direction"` + Field *ValidationOrderField `json:"field"` +} + +// DefaultValidationOrder is the default ordering of Validation. +var DefaultValidationOrder = &ValidationOrder{ + Direction: OrderDirectionAsc, + Field: &ValidationOrderField{ + field: validation.FieldID, + toCursor: func(v *Validation) Cursor { + return Cursor{ID: v.ID} + }, + }, +} + +// ToEdge converts Validation into ValidationEdge. +func (v *Validation) ToEdge(order *ValidationOrder) *ValidationEdge { + if order == nil { + order = DefaultValidationOrder + } + return &ValidationEdge{ + Node: v, + Cursor: order.Field.toCursor(v), + } +} diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index aa8ea9a6..911cd856 100755 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -110,3 +110,6 @@ type Token func(*sql.Selector) // User is the predicate function for user builders. type User func(*sql.Selector) + +// Validation is the predicate function for validation builders. +type Validation func(*sql.Selector) diff --git a/ent/provisioningstep/provisioningstep.go b/ent/provisioningstep/provisioningstep.go index a4e3896d..c704a1b3 100755 --- a/ent/provisioningstep/provisioningstep.go +++ b/ent/provisioningstep/provisioningstep.go @@ -174,6 +174,7 @@ const ( TypeFileDelete Type = "FileDelete" TypeFileDownload Type = "FileDownload" TypeFileExtract Type = "FileExtract" + TypeValidate Type = "Validate" ) func (_type Type) String() string { @@ -183,7 +184,7 @@ func (_type Type) String() string { // TypeValidator is a validator for the "type" field enum values. It is called by the builders before save. func TypeValidator(_type Type) error { switch _type { - case TypeScript, TypeCommand, TypeDNSRecord, TypeFileDelete, TypeFileDownload, TypeFileExtract: + case TypeScript, TypeCommand, TypeDNSRecord, TypeFileDelete, TypeFileDownload, TypeFileExtract, TypeValidate: return nil default: return fmt.Errorf("provisioningstep: invalid enum value for type field: %q", _type) diff --git a/ent/runtime.go b/ent/runtime.go index e9f4831a..c83fa507 100755 --- a/ent/runtime.go +++ b/ent/runtime.go @@ -39,6 +39,7 @@ import ( "github.com/gen0cide/laforge/ent/team" "github.com/gen0cide/laforge/ent/token" "github.com/gen0cide/laforge/ent/user" + "github.com/gen0cide/laforge/ent/validation" "github.com/google/uuid" ) @@ -332,4 +333,22 @@ func init() { userDescID := userFields[0].Descriptor() // user.DefaultID holds the default value on creation for the id field. user.DefaultID = userDescID.Default.(func() uuid.UUID) + validationFields := schema.Validation{}.Fields() + _ = validationFields + // validationDescValidationType is the schema descriptor for validation_type field. + validationDescValidationType := validationFields[2].Descriptor() + // validation.DefaultValidationType holds the default value on creation for the validation_type field. + validation.DefaultValidationType = validationDescValidationType.Default.(string) + // validationDescOutput is the schema descriptor for output field. + validationDescOutput := validationFields[3].Descriptor() + // validation.DefaultOutput holds the default value on creation for the output field. + validation.DefaultOutput = validationDescOutput.Default.(string) + // validationDescErrorMessage is the schema descriptor for error_message field. + validationDescErrorMessage := validationFields[5].Descriptor() + // validation.DefaultErrorMessage holds the default value on creation for the error_message field. + validation.DefaultErrorMessage = validationDescErrorMessage.Default.(string) + // validationDescID is the schema descriptor for id field. + validationDescID := validationFields[0].Descriptor() + // validation.DefaultID holds the default value on creation for the id field. + validation.DefaultID = validationDescID.Default.(func() uuid.UUID) } diff --git a/ent/schema-viz.html b/ent/schema-viz.html index 419a825e..3027da80 100644 --- a/ent/schema-viz.html +++ b/ent/schema-viz.html @@ -4,6 +4,7 @@ ent schema network +