package main import ( "fmt" "io" "os" "regexp" "gopkg.in/yaml.v3" ) type RestartConfig struct { Condition *string `yaml:"condition"` Delay *string `yaml:"delay"` MaxAttempts *int `yaml:"max_attempts"` Window *string `yaml:"window"` } type DeployConfig struct { Policy *RestartConfig `yaml:"restart_policy"` } type ServiceConfig struct { MemLimit *string `yaml:"mem_limit"` Cpus *float64 `yaml:"cpus"` Ports *[]string `yaml:"ports"` Deploy *DeployConfig `yaml:"deploy"` } type Compose struct { Services map[string]ServiceConfig `yaml:"services"` } func main() { filePath := os.Getenv("COMPOSE_FILE_PATH") if filePath == "" { filePath = "./compose.yaml" } f, err := os.Open(filePath) if err != nil { panic(err) } defer f.Close() fd, err := io.ReadAll(f) if err != nil { panic(err) } var data Compose err = yaml.Unmarshal(fd, &data) if err != nil { panic(err) } type report struct { Name string PolicyPresent bool PortSafety bool PortIssues []string ResourceSafety bool ResourceIssues []string } var issues []report for name, serviceConf := range data.Services { r := report{ Name: name, } if serviceConf.Ports != nil { matched, err := regexp.Match(`.*:.*:.*`, []byte((*serviceConf.Ports)[0])) if err != nil { panic(err) } if !matched { r.PortSafety = false r.PortIssues = append(r.PortIssues, "host port does not have an IP addressed and is fully opened") } else { r.PortSafety = true } } else { r.PortSafety = true } r.ResourceSafety = true if serviceConf.MemLimit == nil { r.ResourceSafety = false r.ResourceIssues = append(r.ResourceIssues, "no memory limit set") } if serviceConf.Cpus == nil { r.ResourceSafety = false r.ResourceIssues = append(r.ResourceIssues, "no cpu limit set") } if serviceConf.Deploy != nil && serviceConf.Deploy.Policy != nil { r.PolicyPresent = true } else { r.PolicyPresent = false } fmt.Printf("%+v\n", r) issues = append(issues, r) } }