github.com/boxboat/in-toto-golang@v0.0.3-0.20210303203820-2fa16ecbe6f6/in_toto/rulelib.go (about)

     1  package in_toto
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  )
     7  
     8  // An error message issued in UnpackRule if it receives a malformed rule.
     9  var errorMsg = "Wrong rule format, available formats are:\n" +
    10  	"\tMATCH <pattern> [IN <source-path-prefix>] WITH (MATERIALS|PRODUCTS)" +
    11  	" [IN <destination-path-prefix>] FROM <step>,\n" +
    12  	"\tCREATE <pattern>,\n" +
    13  	"\tDELETE <pattern>,\n" +
    14  	"\tMODIFY <pattern>,\n" +
    15  	"\tALLOW <pattern>,\n" +
    16  	"\tDISALLOW <pattern>,\n" +
    17  	"\tREQUIRE <filename>\n\n"
    18  
    19  /*
    20  UnpackRule parses the passed rule and extracts and returns the information
    21  required for rule processing.  It can be used to verify if a rule has a valid
    22  format.  Available rule formats are:
    23  
    24  	MATCH <pattern> [IN <source-path-prefix>] WITH (MATERIALS|PRODUCTS)
    25  		[IN <destination-path-prefix>] FROM <step>,
    26  	CREATE <pattern>,
    27  	DELETE <pattern>,
    28  	MODIFY <pattern>,
    29  	ALLOW <pattern>,
    30  	DISALLOW <pattern>
    31  
    32  Rule tokens are normalized to lower case before returning.  The returned map
    33  has the following format:
    34  
    35  	{
    36  		"type": "match" | "create" | "delete" |"modify" | "allow" | "disallow"
    37  		"pattern": "<file name pattern>",
    38  		"srcPrefix": "<path or empty string>", // MATCH rule only
    39  		"dstPrefix": "<path or empty string>", // MATCH rule only
    40  		"dstType": "materials" | "products">, // MATCH rule only
    41  		"dstName": "<step name>", // Match rule only
    42  	}
    43  
    44  If the rule does not match any of the available formats the first return value
    45  is nil and the second return value is the error.
    46  */
    47  func UnpackRule(rule []string) (map[string]string, error) {
    48  	// Cache rule len
    49  	ruleLen := len(rule)
    50  
    51  	// Create all lower rule copy to case-insensitively parse out tokens whose
    52  	// position we don't know yet. We keep the original rule to retain the
    53  	// non-token elements' case.
    54  	ruleLower := make([]string, ruleLen)
    55  	for i, val := range rule {
    56  		ruleLower[i] = strings.ToLower(val)
    57  	}
    58  
    59  	switch ruleLower[0] {
    60  	case "create", "modify", "delete", "allow", "disallow", "require":
    61  		if ruleLen != 2 {
    62  			return nil,
    63  				fmt.Errorf("%s Got:\n\t %s", errorMsg, rule)
    64  		}
    65  
    66  		return map[string]string{
    67  			"type":    ruleLower[0],
    68  			"pattern": rule[1],
    69  		}, nil
    70  
    71  	case "match":
    72  		var srcPrefix string
    73  		var dstType string
    74  		var dstPrefix string
    75  		var dstName string
    76  
    77  		// MATCH <pattern> IN <source-path-prefix> WITH (MATERIALS|PRODUCTS) \
    78  		// IN <destination-path-prefix> FROM <step>
    79  		if ruleLen == 10 && ruleLower[2] == "in" &&
    80  			ruleLower[4] == "with" && ruleLower[6] == "in" &&
    81  			ruleLower[8] == "from" {
    82  			srcPrefix = rule[3]
    83  			dstType = ruleLower[5]
    84  			dstPrefix = rule[7]
    85  			dstName = rule[9]
    86  			// MATCH <pattern> IN <source-path-prefix> WITH (MATERIALS|PRODUCTS) \
    87  			// FROM <step>
    88  		} else if ruleLen == 8 && ruleLower[2] == "in" &&
    89  			ruleLower[4] == "with" && ruleLower[6] == "from" {
    90  			srcPrefix = rule[3]
    91  			dstType = ruleLower[5]
    92  			dstPrefix = ""
    93  			dstName = rule[7]
    94  
    95  			// MATCH <pattern> WITH (MATERIALS|PRODUCTS) IN <destination-path-prefix>
    96  			// FROM <step>
    97  		} else if ruleLen == 8 && ruleLower[2] == "with" &&
    98  			ruleLower[4] == "in" && ruleLower[6] == "from" {
    99  			srcPrefix = ""
   100  			dstType = ruleLower[3]
   101  			dstPrefix = rule[5]
   102  			dstName = rule[7]
   103  
   104  			// MATCH <pattern> WITH (MATERIALS|PRODUCTS) FROM <step>
   105  		} else if ruleLen == 6 && ruleLower[2] == "with" &&
   106  			ruleLower[4] == "from" {
   107  			srcPrefix = ""
   108  			dstType = ruleLower[3]
   109  			dstPrefix = ""
   110  			dstName = rule[5]
   111  
   112  		} else {
   113  			return nil,
   114  				fmt.Errorf("%s Got:\n\t %s", errorMsg, rule)
   115  
   116  		}
   117  
   118  		return map[string]string{
   119  			"type":      ruleLower[0],
   120  			"pattern":   rule[1],
   121  			"srcPrefix": srcPrefix,
   122  			"dstPrefix": dstPrefix,
   123  			"dstType":   dstType,
   124  			"dstName":   dstName,
   125  		}, nil
   126  
   127  	default:
   128  		return nil,
   129  			fmt.Errorf("%s Got:\n\t %s", errorMsg, rule)
   130  	}
   131  }