Skip to content

Commit

Permalink
Merge pull request #42 from hennersz/main
Browse files Browse the repository at this point in the history
feat: add generate command
  • Loading branch information
brandtkeller authored Jan 23, 2023
2 parents 6ca3b4a + 9734876 commit ff5860d
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 9 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
lula
compliance_report-*
compliance_report-*
out/
77 changes: 70 additions & 7 deletions src/cmd/execute/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"time"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/kyverno/kyverno/pkg/openapi"
policy2 "github.com/kyverno/kyverno/pkg/policy"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -59,6 +61,11 @@ To execute without creation of any report files
lula execute ./oscal-component.yaml -d
`

var generateHelp = `
To generate kyverno policies:
lula generate ./oscal-component.yaml -o ./out
`

var resourcePaths []string
var cluster, dryRun bool

Expand All @@ -80,13 +87,38 @@ var executeCmd = &cobra.Command{
},
}

func Command() *cobra.Command {
func ExecuteCommand() *cobra.Command {
executeCmd.Flags().StringArrayVarP(&resourcePaths, "resource", "r", []string{}, "Path to resource files")
executeCmd.Flags().BoolVarP(&dryRun, "dry-run", "d", false, "Specifies whether to write reports to filesystem")

return executeCmd
}

var outDirectory string

var generateCmd = &cobra.Command{
Use: "generate",
Short: "generate",
Example: generateHelp,
Run: func(cmd *cobra.Command, componentDefinitionPaths []string) {
if len(componentDefinitionPaths) == 0 {
fmt.Println("Path to the local OSCAL file must be present")
os.Exit(1)
}

err := conductGenerate(componentDefinitionPaths, outDirectory)
if err != nil {
os.Exit(1)
}
},
}

func GenerateCommand() *cobra.Command {
generateCmd.Flags().StringVarP(&outDirectory, "out", "o", "./out/", "Path to output kyverno policies")

return generateCmd
}

func check(e error) {
if e != nil {
panic(e)
Expand All @@ -111,7 +143,7 @@ func conductExecute(componentDefinitionPaths []string, resourcePaths []string, d
implementedReqs, err := getImplementedReqs(oscalComponentDefinitions)
for _, implementedReq := range implementedReqs {

path, err := generatePolicy(implementedReq)
path, err := generatePolicy(implementedReq, "./")
if err != nil {
log.Log.Error(err, "error string")
}
Expand Down Expand Up @@ -156,6 +188,35 @@ func conductExecute(componentDefinitionPaths []string, resourcePaths []string, d
return nil
}

func conductGenerate(componentDefinitionPaths []string, outDirectory string) error {
err := os.MkdirAll(outDirectory, 0755)
if err != nil {
logrus.Error("error creating output directory: ", err)
return err
}

oscalComponentDefinitions, err := oscalComponentDefinitionsFromPaths(componentDefinitionPaths)
if err != nil {
logrus.Error("error getting oscal component definitions: ", err)
return err
}

implementedReqs, err := getImplementedReqs(oscalComponentDefinitions)
if err != nil {
logrus.Error("error getting implemented requirements: ", err)
return err
}

for _, implementedReq := range implementedReqs {
_, err := generatePolicy(implementedReq, outDirectory)
if err != nil {
logrus.Error("error generating policy: ", err)
return err
}
}
return nil
}

// Open files and attempt to unmarshall to oscal component definition structs
func oscalComponentDefinitionsFromPaths(filepaths []string) (oscalComponentDefinitions []types.OscalComponentDefinition, err error) {
for _, path := range filepaths {
Expand Down Expand Up @@ -201,17 +262,18 @@ func getImplementedReqs(componentDefinitions []types.OscalComponentDefinition) (
// Turn a ruleset into a ClusterPolicy resource for ability to use Kyverno applyCommandHelper without modification
// This needs to copy the rules into a Cluster Policy resource (yaml) and write to individual files
// Kyverno will perform applying these and generating pass/fail results
func generatePolicy(implementedRequirement types.ImplementedRequirementsCustom) (policyPath string, err error) {
func generatePolicy(implementedRequirement types.ImplementedRequirementsCustom, outDir string) (policyPath string, err error) {

if len(implementedRequirement.Rules) != 0 {
// fmt.Printf("%v", implementedRequirement.Rules[0].Validation.RawPattern)
policyName := strings.ToLower(implementedRequirement.UUID)
policy := v1.ClusterPolicy{
TypeMeta: metav1.TypeMeta{
Kind: "ClusterPolicy",
APIVersion: "kyverno.io/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: implementedRequirement.UUID,
Name: policyName,
},
Spec: v1.Spec{
Rules: implementedRequirement.Rules,
Expand All @@ -223,12 +285,13 @@ func generatePolicy(implementedRequirement types.ImplementedRequirementsCustom)
fmt.Printf("Error while Marshaling. %v", err)
}

fileName := implementedRequirement.UUID + ".yaml"
err = ioutil.WriteFile(fileName, yamlData, 0644)
fileName := policyName + ".yaml"
policyPath = path.Join(outDir, fileName)
err = ioutil.WriteFile(policyPath, yamlData, 0644)
if err != nil {
logrus.Error(err)
panic("Unable to write data into the file")
}
policyPath = "./" + implementedRequirement.UUID + ".yaml"
}

return
Expand Down
3 changes: 2 additions & 1 deletion src/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ var rootCmd = &cobra.Command{
func Execute() {

commands := []*cobra.Command{
execute.Command(),
execute.ExecuteCommand(),
execute.GenerateCommand(),
}

rootCmd.AddCommand(commands...)
Expand Down

0 comments on commit ff5860d

Please sign in to comment.