2020-05-29 15:32:29 +05:30
package common
import (
2020-09-01 09:38:49 -07:00
"bufio"
2022-05-11 14:04:40 +02:00
"context"
2020-05-29 15:32:29 +05:30
"encoding/json"
"fmt"
2022-09-30 15:25:19 +08:00
"io"
2021-02-08 23:38:06 +05:30
"net/http"
2020-10-19 12:36:55 -07:00
"os"
"path/filepath"
2021-02-02 18:43:19 +05:30
"strings"
2020-08-31 19:32:00 +05:30
2021-02-07 20:26:56 -08:00
"github.com/go-git/go-billy/v5"
2022-05-17 13:12:43 +02:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
2022-04-14 17:50:18 +05:30
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
2023-07-03 15:22:05 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/values"
2022-04-25 20:20:40 +08:00
"github.com/kyverno/kyverno/pkg/autogen"
2022-05-25 19:56:22 +05:30
"github.com/kyverno/kyverno/pkg/background/generate"
2022-08-31 14:03:47 +08:00
"github.com/kyverno/kyverno/pkg/clients/dclient"
2023-01-02 18:14:40 +01:00
"github.com/kyverno/kyverno/pkg/config"
2021-02-07 20:26:56 -08:00
"github.com/kyverno/kyverno/pkg/engine"
2023-06-10 11:20:34 +02:00
"github.com/kyverno/kyverno/pkg/engine/adapters"
2023-01-30 12:41:09 +01:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2023-04-13 13:29:40 +02:00
"github.com/kyverno/kyverno/pkg/engine/jmespath"
2023-03-03 19:32:40 +08:00
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
2023-04-18 14:08:17 +02:00
"github.com/kyverno/kyverno/pkg/logging"
2023-03-24 11:01:49 +01:00
datautils "github.com/kyverno/kyverno/pkg/utils/data"
2022-12-09 22:15:23 +05:30
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2022-09-06 17:16:44 +02:00
yamlutils "github.com/kyverno/kyverno/pkg/utils/yaml"
2021-02-07 20:26:56 -08:00
yamlv2 "gopkg.in/yaml.v2"
2023-05-10 11:12:53 +03:00
"k8s.io/api/admissionregistration/v1alpha1"
2022-12-09 22:15:23 +05:30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-11-17 13:07:30 -08:00
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2022-05-25 19:56:22 +05:30
"k8s.io/apimachinery/pkg/runtime"
2023-03-22 11:18:11 +01:00
"k8s.io/apimachinery/pkg/runtime/schema"
2020-11-17 13:07:30 -08:00
"k8s.io/apimachinery/pkg/util/yaml"
2020-05-29 15:32:29 +05:30
)
2023-04-18 14:08:17 +02:00
var log = logging . WithName ( "kubectl-kyverno" )
2021-08-31 21:18:54 +05:30
type ResultCounts struct {
Pass int
Fail int
Warn int
Error int
Skip int
}
2021-02-02 18:43:19 +05:30
2022-10-19 22:09:15 +05:30
type ApplyPolicyConfig struct {
Policy kyvernov1 . PolicyInterface
2023-05-10 11:12:53 +03:00
ValidatingAdmissionPolicy v1alpha1 . ValidatingAdmissionPolicy
2022-10-19 22:09:15 +05:30
Resource * unstructured . Unstructured
MutateLogPath string
MutateLogPathIsDir bool
Variables map [ string ] interface { }
UserInfo kyvernov1beta1 . RequestInfo
PolicyReport bool
NamespaceSelectorMap map [ string ] map [ string ] string
Stdin bool
Rc * ResultCounts
PrintPatchResource bool
RuleToCloneSourceResource map [ string ] string
Client dclient . Interface
2022-11-21 09:21:32 -05:00
AuditWarn bool
2023-07-03 15:22:05 +02:00
Subresources [ ] values . Subresource
2022-10-19 22:09:15 +05:30
}
2021-11-03 11:16:55 -07:00
// HasVariables - check for variables in the policy
2022-05-17 13:12:43 +02:00
func HasVariables ( policy kyvernov1 . PolicyInterface ) [ ] [ ] string {
2021-11-03 11:16:55 -07:00
policyRaw , _ := json . Marshal ( policy )
2023-03-03 19:32:40 +08:00
matches := regex . RegexVariables . FindAllStringSubmatch ( string ( policyRaw ) , - 1 )
2021-11-03 11:16:55 -07:00
return matches
}
2021-08-31 21:18:54 +05:30
// GetPolicies - Extracting the policies from multiple YAML
2023-05-10 11:12:53 +03:00
func GetPolicies ( paths [ ] string ) ( policies [ ] kyvernov1 . PolicyInterface , validatingAdmissionPolicies [ ] v1alpha1 . ValidatingAdmissionPolicy , errors [ ] error ) {
2020-11-03 01:25:32 +05:30
for _ , path := range paths {
2023-04-18 14:08:17 +02:00
log . V ( 5 ) . Info ( "reading policies" , "path" , path )
2020-12-07 11:26:04 -08:00
2021-02-08 23:38:06 +05:30
var (
fileDesc os . FileInfo
err error
)
2021-10-29 16:06:03 +01:00
isHTTPPath := IsHTTPRegex . MatchString ( path )
2021-02-08 23:38:06 +05:30
// path clean and retrieving file info can be possible if it's not an HTTP URL
2021-10-29 16:06:03 +01:00
if ! isHTTPPath {
2021-02-08 23:38:06 +05:30
path = filepath . Clean ( path )
fileDesc , err = os . Stat ( path )
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
2020-10-21 20:05:05 +05:30
}
2020-12-07 11:26:04 -08:00
2021-02-08 23:38:06 +05:30
// apply file from a directory is possible only if the path is not HTTP URL
2021-10-29 16:06:03 +01:00
if ! isHTTPPath && fileDesc . IsDir ( ) {
2022-09-30 15:25:19 +08:00
files , err := os . ReadDir ( path )
2020-10-07 06:20:53 +05:30
if err != nil {
2021-02-08 23:38:06 +05:30
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
2020-12-07 11:26:04 -08:00
continue
2020-10-07 06:20:53 +05:30
}
2020-12-07 11:26:04 -08:00
2020-11-03 01:25:32 +05:30
listOfFiles := make ( [ ] string , 0 )
for _ , file := range files {
2020-12-07 11:26:04 -08:00
ext := filepath . Ext ( file . Name ( ) )
if ext == "" || ext == ".yaml" || ext == ".yml" {
listOfFiles = append ( listOfFiles , filepath . Join ( path , file . Name ( ) ) )
}
2020-11-01 23:18:58 +05:30
}
2023-05-10 11:12:53 +03:00
policiesFromDir , admissionPoliciesFromDir , errorsFromDir := GetPolicies ( listOfFiles )
2020-12-07 11:26:04 -08:00
errors = append ( errors , errorsFromDir ... )
2020-11-03 01:25:32 +05:30
policies = append ( policies , policiesFromDir ... )
2023-05-10 11:12:53 +03:00
validatingAdmissionPolicies = append ( validatingAdmissionPolicies , admissionPoliciesFromDir ... )
2020-11-03 01:25:32 +05:30
} else {
2021-02-08 23:38:06 +05:30
var fileBytes [ ] byte
2021-10-29 16:06:03 +01:00
if isHTTPPath {
2021-10-14 00:05:13 +02:00
// We accept here that a random URL might be called based on user provided input.
2022-05-11 14:04:40 +02:00
req , err := http . NewRequestWithContext ( context . TODO ( ) , http . MethodGet , path , nil )
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
resp , err := http . DefaultClient . Do ( req )
2021-02-08 23:38:06 +05:30
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
defer resp . Body . Close ( )
if resp . StatusCode != http . StatusOK {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
2022-09-30 15:25:19 +08:00
fileBytes , err = io . ReadAll ( resp . Body )
2021-02-08 23:38:06 +05:30
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
} else {
2021-10-13 10:48:45 -07:00
path = filepath . Clean ( path )
2021-10-14 00:05:13 +02:00
// We accept the risk of including a user provided file here.
2022-09-30 15:25:19 +08:00
fileBytes , err = os . ReadFile ( path ) // #nosec G304
2021-02-08 23:38:06 +05:30
if err != nil {
err := fmt . Errorf ( "failed to process %v: %v" , path , err . Error ( ) )
errors = append ( errors , err )
continue
}
2020-11-03 01:25:32 +05:30
}
2020-12-07 11:26:04 -08:00
2023-05-10 11:12:53 +03:00
policiesFromFile , admissionPoliciesFromFile , errFromFile := yamlutils . GetPolicy ( fileBytes )
2020-12-07 11:26:04 -08:00
if errFromFile != nil {
err := fmt . Errorf ( "failed to process %s: %v" , path , errFromFile . Error ( ) )
errors = append ( errors , err )
continue
2020-11-01 23:18:58 +05:30
}
2020-10-21 20:05:05 +05:30
2020-12-07 11:26:04 -08:00
policies = append ( policies , policiesFromFile ... )
2023-05-10 11:12:53 +03:00
validatingAdmissionPolicies = append ( validatingAdmissionPolicies , admissionPoliciesFromFile ... )
2020-11-01 23:18:58 +05:30
}
2020-10-21 20:05:05 +05:30
}
2023-04-18 14:08:17 +02:00
log . V ( 3 ) . Info ( "read policies" , "policies" , len ( policies ) , "errors" , len ( errors ) )
2023-05-10 11:12:53 +03:00
return policies , validatingAdmissionPolicies , errors
2020-05-29 15:32:29 +05:30
}
2020-07-07 16:20:55 +05:30
2020-10-07 06:20:53 +05:30
// IsInputFromPipe - check if input is passed using pipe
func IsInputFromPipe ( ) bool {
fileInfo , _ := os . Stdin . Stat ( )
return fileInfo . Mode ( ) & os . ModeCharDevice == 0
}
2021-02-02 18:43:19 +05:30
2021-07-24 00:02:48 +05:30
// RemoveDuplicateAndObjectVariables - remove duplicate variables
func RemoveDuplicateAndObjectVariables ( matches [ ] [ ] string ) string {
2021-02-02 18:43:19 +05:30
var variableStr string
for _ , m := range matches {
for _ , v := range m {
foundVariable := strings . Contains ( variableStr , v )
if ! foundVariable {
2022-01-04 17:36:33 -08:00
if ! strings . Contains ( v , "request.object" ) && ! strings . Contains ( v , "element" ) && v == "elementIndex" {
2021-07-24 00:02:48 +05:30
variableStr = variableStr + " " + v
}
2021-02-02 18:43:19 +05:30
}
}
}
return variableStr
}
2023-07-03 12:04:07 +02:00
func GetVariable (
variablesString [ ] string ,
valuesFile string ,
fs billy . Filesystem ,
isGit bool ,
policyResourcePath string ,
2023-07-03 15:22:05 +02:00
) ( map [ string ] string , map [ string ] string , map [ string ] map [ string ] values . Resource , map [ string ] map [ string ] string , [ ] values . Subresource , error ) {
valuesMapResource := make ( map [ string ] map [ string ] values . Resource )
valuesMapRule := make ( map [ string ] map [ string ] values . Rule )
2021-03-10 02:15:45 +05:30
namespaceSelectorMap := make ( map [ string ] map [ string ] string )
2021-02-03 18:24:50 +05:30
variables := make ( map [ string ] string )
2023-07-03 15:22:05 +02:00
subresources := make ( [ ] values . Subresource , 0 )
2021-09-20 22:16:57 +05:30
globalValMap := make ( map [ string ] string )
2021-08-01 16:27:47 +05:30
reqObjVars := ""
2021-07-28 10:52:32 +05:30
2023-07-03 12:04:07 +02:00
for _ , kvpair := range variablesString {
kvs := strings . Split ( strings . Trim ( kvpair , " " ) , "=" )
if strings . Contains ( kvs [ 0 ] , "request.object" ) {
if ! strings . Contains ( reqObjVars , kvs [ 0 ] ) {
reqObjVars = reqObjVars + "," + kvs [ 0 ]
2021-07-24 00:02:48 +05:30
}
2023-07-03 12:04:07 +02:00
continue
2021-02-02 18:43:19 +05:30
}
2023-07-03 12:04:07 +02:00
variables [ strings . Trim ( kvs [ 0 ] , " " ) ] = strings . Trim ( kvs [ 1 ] , " " )
2021-02-02 18:43:19 +05:30
}
2021-07-24 00:02:48 +05:30
2021-02-02 18:43:19 +05:30
if valuesFile != "" {
2023-07-03 15:22:05 +02:00
vals , err := values . Load ( fs , filepath . Join ( policyResourcePath , valuesFile ) )
2021-02-02 18:43:19 +05:30
if err != nil {
2023-07-03 15:22:05 +02:00
fmt . Printf ( "Unable to load variable file: %s. error: %s \n" , valuesFile , err )
2022-12-09 22:15:23 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , subresources , sanitizederror . NewWithError ( "unable to read yaml" , err )
2021-02-02 18:43:19 +05:30
}
2023-07-03 15:22:05 +02:00
if vals . GlobalValues == nil {
vals . GlobalValues = make ( map [ string ] string )
vals . GlobalValues [ "request.operation" ] = "CREATE"
2023-04-18 14:08:17 +02:00
log . V ( 3 ) . Info ( "Defaulting request.operation to CREATE" )
2022-05-25 19:29:53 +05:30
} else {
2023-07-03 15:22:05 +02:00
if val , ok := vals . GlobalValues [ "request.operation" ] ; ok {
2022-05-25 19:29:53 +05:30
if val == "" {
2023-07-03 15:22:05 +02:00
vals . GlobalValues [ "request.operation" ] = "CREATE"
log . V ( 3 ) . Info ( "Globally request.operation value provided by the user is empty, defaulting it to CREATE" , "request.opearation: " , vals . GlobalValues )
2022-05-25 19:29:53 +05:30
}
}
}
2023-07-03 15:22:05 +02:00
globalValMap = vals . GlobalValues
2021-09-20 22:16:57 +05:30
2023-07-03 15:22:05 +02:00
for _ , p := range vals . Policies {
resourceMap := make ( map [ string ] values . Resource )
2021-02-02 18:43:19 +05:30
for _ , r := range p . Resources {
2021-11-18 20:39:35 +05:30
if val , ok := r . Values [ "request.operation" ] ; ok {
if val == "" {
r . Values [ "request.operation" ] = "CREATE"
2023-04-18 14:08:17 +02:00
log . V ( 3 ) . Info ( "No request.operation found, defaulting it to CREATE" , "policy" , p . Name )
2021-11-18 20:39:35 +05:30
}
}
2021-07-28 10:52:32 +05:30
for variableInFile := range r . Values {
2021-07-24 00:02:48 +05:30
if strings . Contains ( variableInFile , "request.object" ) {
2021-08-01 16:27:47 +05:30
if ! strings . Contains ( reqObjVars , variableInFile ) {
reqObjVars = reqObjVars + "," + variableInFile
}
delete ( r . Values , variableInFile )
continue
2021-07-24 00:02:48 +05:30
}
}
2021-04-29 22:39:44 +05:30
resourceMap [ r . Name ] = r
}
valuesMapResource [ p . Name ] = resourceMap
if p . Rules != nil {
2023-07-03 15:22:05 +02:00
ruleMap := make ( map [ string ] values . Rule )
2021-04-29 22:39:44 +05:30
for _ , r := range p . Rules {
ruleMap [ r . Name ] = r
}
valuesMapRule [ p . Name ] = ruleMap
2021-02-02 18:43:19 +05:30
}
}
2021-03-10 02:15:45 +05:30
2023-07-03 15:22:05 +02:00
for _ , n := range vals . NamespaceSelectors {
2021-03-10 02:15:45 +05:30
namespaceSelectorMap [ n . Name ] = n . Labels
}
2022-12-09 22:15:23 +05:30
2023-07-03 15:22:05 +02:00
subresources = vals . Subresources
2021-02-02 18:43:19 +05:30
}
2021-08-01 16:27:47 +05:30
if reqObjVars != "" {
2022-12-09 22:15:23 +05:30
fmt . Printf ( "\nNOTICE: request.object.* variables are automatically parsed from the supplied resource. Ignoring value of variables `%v`.\n" , reqObjVars )
2021-08-01 16:27:47 +05:30
}
2022-05-25 19:29:53 +05:30
if globalValMap != nil {
2022-12-09 22:15:23 +05:30
if _ , ok := globalValMap [ "request.operation" ] ; ! ok {
2022-11-22 20:17:06 +08:00
globalValMap [ "request.operation" ] = "CREATE"
2023-04-18 14:08:17 +02:00
log . V ( 3 ) . Info ( "Defaulting request.operation to CREATE" )
2022-11-22 20:17:06 +08:00
}
2022-05-25 19:29:53 +05:30
}
2022-03-02 08:29:33 +01:00
storePolicies := make ( [ ] store . Policy , 0 )
2021-04-29 22:39:44 +05:30
for policyName , ruleMap := range valuesMapRule {
storeRules := make ( [ ] store . Rule , 0 )
for _ , rule := range ruleMap {
storeRules = append ( storeRules , store . Rule {
2022-04-25 22:06:31 +05:30
Name : rule . Name ,
Values : rule . Values ,
2022-12-12 11:24:13 -08:00
ForEachValues : rule . ForeachValues ,
2021-04-29 22:39:44 +05:30
} )
}
2022-03-02 08:29:33 +01:00
storePolicies = append ( storePolicies , store . Policy {
2021-04-29 22:39:44 +05:30
Name : policyName ,
Rules : storeRules ,
} )
}
2023-01-30 16:30:47 +01:00
store . SetPolicies ( storePolicies ... )
2021-04-29 22:39:44 +05:30
2022-12-09 22:15:23 +05:30
return variables , globalValMap , valuesMapResource , namespaceSelectorMap , subresources , nil
2021-02-02 18:43:19 +05:30
}
2023-04-12 14:51:03 +02:00
func ProcessValidateEngineResponse ( policy kyvernov1 . PolicyInterface , validateResponse engineapi . EngineResponse , resPath string , rc * ResultCounts , policyReport bool , auditWarn bool ) {
printCount := 0
for _ , policyRule := range autogen . ComputeRules ( policy ) {
ruleFoundInEngineResponse := false
if ! policyRule . HasValidate ( ) && ! policyRule . HasVerifyImageChecks ( ) && ! policyRule . HasVerifyImages ( ) {
continue
}
for i , valResponseRule := range validateResponse . PolicyResponse . Rules {
if policyRule . Name == valResponseRule . Name ( ) {
ruleFoundInEngineResponse = true
switch valResponseRule . Status ( ) {
case engineapi . RuleStatusPass :
rc . Pass ++
case engineapi . RuleStatusFail :
auditWarning := false
ann := policy . GetAnnotations ( )
if scored , ok := ann [ kyvernov1 . AnnotationPolicyScored ] ; ok && scored == "false" {
rc . Warn ++
break
} else if auditWarn && validateResponse . GetValidationFailureAction ( ) . Audit ( ) {
rc . Warn ++
auditWarning = true
} else {
rc . Fail ++
}
if ! policyReport {
if printCount < 1 {
if auditWarning {
fmt . Printf ( "\npolicy %s -> resource %s failed as audit warning: \n" , policy . GetName ( ) , resPath )
} else {
fmt . Printf ( "\npolicy %s -> resource %s failed: \n" , policy . GetName ( ) , resPath )
}
printCount ++
}
fmt . Printf ( "%d. %s: %s \n" , i + 1 , valResponseRule . Name ( ) , valResponseRule . Message ( ) )
}
case engineapi . RuleStatusError :
2023-07-05 17:44:59 +02:00
fmt . Printf ( "\npolicy %s -> resource %s error: %s\n" , policy . GetName ( ) , resPath , valResponseRule . Message ( ) )
2023-04-12 14:51:03 +02:00
rc . Error ++
case engineapi . RuleStatusWarn :
rc . Warn ++
case engineapi . RuleStatusSkip :
rc . Skip ++
}
continue
}
}
if ! ruleFoundInEngineResponse {
rc . Skip ++
}
}
2021-02-02 18:43:19 +05:30
}
// PrintMutatedOutput - function to print output in provided file or directory
func PrintMutatedOutput ( mutateLogPath string , mutateLogPathIsDir bool , yaml string , fileName string ) error {
var f * os . File
var err error
yaml = yaml + ( "\n---\n\n" )
2021-10-13 10:48:45 -07:00
mutateLogPath = filepath . Clean ( mutateLogPath )
2021-02-02 18:43:19 +05:30
if ! mutateLogPathIsDir {
2021-07-09 18:01:46 -07:00
// truncation for the case when mutateLogPath is a file (not a directory) is handled under pkg/kyverno/apply/test_command.go
2022-05-17 08:19:03 +02:00
f , err = os . OpenFile ( mutateLogPath , os . O_APPEND | os . O_WRONLY , 0 o600 ) // #nosec G304
2021-02-02 18:43:19 +05:30
} else {
2022-05-17 08:19:03 +02:00
f , err = os . OpenFile ( mutateLogPath + "/" + fileName + ".yaml" , os . O_CREATE | os . O_WRONLY , 0 o600 ) // #nosec G304
2021-02-02 18:43:19 +05:30
}
if err != nil {
return err
}
if _ , err := f . Write ( [ ] byte ( yaml ) ) ; err != nil {
2021-10-14 00:05:13 +02:00
closeErr := f . Close ( )
if closeErr != nil {
2023-04-18 14:08:17 +02:00
log . Error ( closeErr , "failed to close file" )
2021-10-14 00:05:13 +02:00
}
2021-02-02 18:43:19 +05:30
return err
}
if err := f . Close ( ) ; err != nil {
return err
}
return nil
}
// GetPoliciesFromPaths - get policies according to the resource path
2023-05-10 11:12:53 +03:00
func GetPoliciesFromPaths ( fs billy . Filesystem , dirPath [ ] string , isGit bool , policyResourcePath string ) ( policies [ ] kyvernov1 . PolicyInterface , validatingAdmissionPolicies [ ] v1alpha1 . ValidatingAdmissionPolicy , err error ) {
2021-02-02 18:43:19 +05:30
if isGit {
for _ , pp := range dirPath {
2021-06-22 18:56:44 +05:30
filep , err := fs . Open ( filepath . Join ( policyResourcePath , pp ) )
2021-02-18 01:00:41 +05:30
if err != nil {
fmt . Printf ( "Error: file not available with path %s: %v" , filep . Name ( ) , err . Error ( ) )
continue
}
2022-09-30 15:25:19 +08:00
bytes , err := io . ReadAll ( filep )
2021-02-02 18:43:19 +05:30
if err != nil {
fmt . Printf ( "Error: failed to read file %s: %v" , filep . Name ( ) , err . Error ( ) )
2021-02-18 01:00:41 +05:30
continue
2021-02-02 18:43:19 +05:30
}
policyBytes , err := yaml . ToJSON ( bytes )
if err != nil {
fmt . Printf ( "failed to convert to JSON: %v" , err )
continue
}
2023-05-10 11:12:53 +03:00
policiesFromFile , admissionPoliciesFromFile , errFromFile := yamlutils . GetPolicy ( policyBytes )
2021-02-02 18:43:19 +05:30
if errFromFile != nil {
2022-05-09 18:55:35 +02:00
fmt . Printf ( "failed to process : %v" , errFromFile . Error ( ) )
2021-02-02 18:43:19 +05:30
continue
}
policies = append ( policies , policiesFromFile ... )
2023-05-10 11:12:53 +03:00
validatingAdmissionPolicies = append ( validatingAdmissionPolicies , admissionPoliciesFromFile ... )
2021-02-02 18:43:19 +05:30
}
} else {
if len ( dirPath ) > 0 && dirPath [ 0 ] == "-" {
if IsInputFromPipe ( ) {
policyStr := ""
scanner := bufio . NewScanner ( os . Stdin )
for scanner . Scan ( ) {
policyStr = policyStr + scanner . Text ( ) + "\n"
}
yamlBytes := [ ] byte ( policyStr )
2023-05-10 11:12:53 +03:00
policies , validatingAdmissionPolicies , err = yamlutils . GetPolicy ( yamlBytes )
2021-02-02 18:43:19 +05:30
if err != nil {
2023-05-10 11:12:53 +03:00
return nil , nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
2021-02-02 18:43:19 +05:30
}
}
} else {
var errors [ ] error
2023-05-10 11:12:53 +03:00
policies , validatingAdmissionPolicies , errors = GetPolicies ( dirPath )
if len ( policies ) == 0 && len ( validatingAdmissionPolicies ) == 0 {
2021-02-02 18:43:19 +05:30
if len ( errors ) > 0 {
2023-05-10 11:12:53 +03:00
return nil , nil , sanitizederror . NewWithErrors ( "failed to read file" , errors )
2021-02-02 18:43:19 +05:30
}
2023-05-10 11:12:53 +03:00
return nil , nil , sanitizederror . New ( fmt . Sprintf ( "no file found in paths %v" , dirPath ) )
2021-02-02 18:43:19 +05:30
}
2023-04-18 14:08:17 +02:00
if len ( errors ) > 0 && log . V ( 1 ) . Enabled ( ) {
2021-02-02 18:43:19 +05:30
fmt . Printf ( "ignoring errors: \n" )
for _ , e := range errors {
fmt . Printf ( " %v \n" , e . Error ( ) )
}
}
}
2021-02-07 20:26:56 -08:00
}
2021-02-02 18:43:19 +05:30
return
}
// GetResourceAccordingToResourcePath - get resources according to the resource path
2021-02-07 20:26:56 -08:00
func GetResourceAccordingToResourcePath ( fs billy . Filesystem , resourcePaths [ ] string ,
2023-05-10 11:12:53 +03:00
cluster bool , policies [ ] kyvernov1 . PolicyInterface , validatingAdmissionPolicies [ ] v1alpha1 . ValidatingAdmissionPolicy , dClient dclient . Interface , namespace string , policyReport bool , isGit bool , policyResourcePath string ,
2022-05-17 08:19:03 +02:00
) ( resources [ ] * unstructured . Unstructured , err error ) {
2021-02-02 18:43:19 +05:30
if isGit {
2021-06-22 18:56:44 +05:30
resources , err = GetResourcesWithTest ( fs , policies , resourcePaths , isGit , policyResourcePath )
2021-02-02 18:43:19 +05:30
if err != nil {
return nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
}
} else {
if len ( resourcePaths ) > 0 && resourcePaths [ 0 ] == "-" {
if IsInputFromPipe ( ) {
resourceStr := ""
scanner := bufio . NewScanner ( os . Stdin )
for scanner . Scan ( ) {
resourceStr = resourceStr + scanner . Text ( ) + "\n"
}
yamlBytes := [ ] byte ( resourceStr )
resources , err = GetResource ( yamlBytes )
if err != nil {
return nil , sanitizederror . NewWithError ( "failed to extract the resources" , err )
}
}
2022-03-21 19:31:23 +05:30
} else {
if len ( resourcePaths ) > 0 {
fileDesc , err := os . Stat ( resourcePaths [ 0 ] )
2022-03-15 13:30:59 +05:30
if err != nil {
2022-03-21 19:31:23 +05:30
return nil , err
2022-03-15 13:30:59 +05:30
}
2022-03-21 19:31:23 +05:30
if fileDesc . IsDir ( ) {
2022-09-30 15:25:19 +08:00
files , err := os . ReadDir ( resourcePaths [ 0 ] )
2022-03-21 19:31:23 +05:30
if err != nil {
return nil , sanitizederror . NewWithError ( fmt . Sprintf ( "failed to parse %v" , resourcePaths [ 0 ] ) , err )
}
listOfFiles := make ( [ ] string , 0 )
for _ , file := range files {
ext := filepath . Ext ( file . Name ( ) )
if ext == ".yaml" || ext == ".yml" {
listOfFiles = append ( listOfFiles , filepath . Join ( resourcePaths [ 0 ] , file . Name ( ) ) )
}
2022-03-15 13:30:59 +05:30
}
2022-03-21 19:31:23 +05:30
resourcePaths = listOfFiles
2022-03-15 13:30:59 +05:30
}
}
2022-03-21 19:31:23 +05:30
2023-05-10 11:12:53 +03:00
resources , err = GetResources ( policies , validatingAdmissionPolicies , resourcePaths , dClient , cluster , namespace , policyReport )
2021-02-02 18:43:19 +05:30
if err != nil {
return resources , err
}
}
}
return resources , err
2021-02-07 20:26:56 -08:00
}
2021-09-02 00:02:55 +05:30
2023-01-30 12:41:09 +01:00
func updateResultCounts ( policy kyvernov1 . PolicyInterface , engineResponse * engineapi . EngineResponse , resPath string , rc * ResultCounts , auditWarn bool ) {
2021-09-02 03:54:02 +05:30
printCount := 0
2022-03-28 16:01:27 +02:00
for _ , policyRule := range autogen . ComputeRules ( policy ) {
2021-09-02 03:54:02 +05:30
ruleFoundInEngineResponse := false
2022-04-27 08:09:52 -07:00
for i , ruleResponse := range engineResponse . PolicyResponse . Rules {
2023-04-05 12:35:38 +02:00
if policyRule . Name == ruleResponse . Name ( ) {
2021-09-02 03:54:02 +05:30
ruleFoundInEngineResponse = true
2022-05-04 09:41:59 +05:30
2023-04-05 12:35:38 +02:00
if ruleResponse . Status ( ) == engineapi . RuleStatusPass {
2021-09-02 03:54:02 +05:30
rc . Pass ++
} else {
if printCount < 1 {
2022-04-27 08:09:52 -07:00
fmt . Println ( "\ninvalid resource" , "policy" , policy . GetName ( ) , "resource" , resPath )
2021-09-02 03:54:02 +05:30
printCount ++
}
2023-04-05 12:35:38 +02:00
fmt . Printf ( "%d. %s - %s\n" , i + 1 , ruleResponse . Name ( ) , ruleResponse . Message ( ) )
2022-11-21 09:21:32 -05:00
if auditWarn && engineResponse . GetValidationFailureAction ( ) . Audit ( ) {
rc . Warn ++
} else {
rc . Fail ++
}
2021-09-02 03:54:02 +05:30
}
continue
}
}
2022-04-27 08:09:52 -07:00
2021-09-02 03:54:02 +05:30
if ! ruleFoundInEngineResponse {
rc . Skip ++
}
}
}
2021-09-02 23:11:35 +05:30
2022-05-17 13:12:43 +02:00
func SetInStoreContext ( mutatedPolicies [ ] kyvernov1 . PolicyInterface , variables map [ string ] string ) map [ string ] string {
2022-03-02 08:29:33 +01:00
storePolicies := make ( [ ] store . Policy , 0 )
2021-09-02 23:11:35 +05:30
for _ , policy := range mutatedPolicies {
storeRules := make ( [ ] store . Rule , 0 )
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2022-05-07 21:30:11 +01:00
contextVal := make ( map [ string ] interface { } )
2021-09-02 23:11:35 +05:30
if len ( rule . Context ) != 0 {
for _ , contextVar := range rule . Context {
for k , v := range variables {
if strings . HasPrefix ( k , contextVar . Name ) {
contextVal [ k ] = v
delete ( variables , k )
}
}
}
storeRules = append ( storeRules , store . Rule {
Name : rule . Name ,
Values : contextVal ,
} )
}
}
2022-03-02 08:29:33 +01:00
storePolicies = append ( storePolicies , store . Policy {
2022-03-31 08:44:00 +02:00
Name : policy . GetName ( ) ,
2021-09-02 23:11:35 +05:30
Rules : storeRules ,
} )
}
2023-01-30 16:30:47 +01:00
store . SetPolicies ( storePolicies ... )
2021-09-02 23:11:35 +05:30
return variables
}
2021-09-03 12:32:12 +05:30
2023-01-30 12:41:09 +01:00
func processMutateEngineResponse ( c ApplyPolicyConfig , mutateResponse * engineapi . EngineResponse , resPath string ) error {
2021-09-03 12:41:05 +05:30
var policyHasMutate bool
2022-10-19 22:09:15 +05:30
for _ , rule := range autogen . ComputeRules ( c . Policy ) {
2021-09-03 12:41:05 +05:30
if rule . HasMutate ( ) {
policyHasMutate = true
}
}
2021-09-03 16:41:13 +05:30
if ! policyHasMutate {
return nil
}
2021-09-03 12:41:05 +05:30
2021-09-03 16:41:13 +05:30
printCount := 0
printMutatedRes := false
2022-10-19 22:09:15 +05:30
for _ , policyRule := range autogen . ComputeRules ( c . Policy ) {
2021-09-03 16:41:13 +05:30
ruleFoundInEngineResponse := false
for i , mutateResponseRule := range mutateResponse . PolicyResponse . Rules {
2023-04-05 12:35:38 +02:00
if policyRule . Name == mutateResponseRule . Name ( ) {
2021-09-03 16:41:13 +05:30
ruleFoundInEngineResponse = true
2023-04-05 12:35:38 +02:00
if mutateResponseRule . Status ( ) == engineapi . RuleStatusPass {
2022-10-19 22:09:15 +05:30
c . Rc . Pass ++
2021-09-03 16:41:13 +05:30
printMutatedRes = true
2023-04-05 12:35:38 +02:00
} else if mutateResponseRule . Status ( ) == engineapi . RuleStatusSkip {
2022-10-19 22:09:15 +05:30
fmt . Printf ( "\nskipped mutate policy %s -> resource %s" , c . Policy . GetName ( ) , resPath )
c . Rc . Skip ++
2023-04-05 12:35:38 +02:00
} else if mutateResponseRule . Status ( ) == engineapi . RuleStatusError {
fmt . Printf ( "\nerror while applying mutate policy %s -> resource %s\nerror: %s" , c . Policy . GetName ( ) , resPath , mutateResponseRule . Message ( ) )
2022-10-19 22:09:15 +05:30
c . Rc . Error ++
2021-09-03 16:41:13 +05:30
} else {
if printCount < 1 {
2022-10-19 22:09:15 +05:30
fmt . Printf ( "\nfailed to apply mutate policy %s -> resource %s" , c . Policy . GetName ( ) , resPath )
2021-09-03 16:41:13 +05:30
printCount ++
2021-09-03 12:32:12 +05:30
}
2023-04-05 12:35:38 +02:00
fmt . Printf ( "%d. %s - %s \n" , i + 1 , mutateResponseRule . Name ( ) , mutateResponseRule . Message ( ) )
2022-10-19 22:09:15 +05:30
c . Rc . Fail ++
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
continue
2021-09-03 12:32:12 +05:30
}
}
2021-09-03 16:41:13 +05:30
if ! ruleFoundInEngineResponse {
2022-10-19 22:09:15 +05:30
c . Rc . Skip ++
2021-09-03 16:41:13 +05:30
}
}
2021-09-03 12:32:12 +05:30
2022-10-19 22:09:15 +05:30
if printMutatedRes && c . PrintPatchResource {
2021-09-03 16:41:13 +05:30
yamlEncodedResource , err := yamlv2 . Marshal ( mutateResponse . PatchedResource . Object )
if err != nil {
return sanitizederror . NewWithError ( "failed to marshal" , err )
}
2021-09-03 12:32:12 +05:30
2022-10-19 22:09:15 +05:30
if c . MutateLogPath == "" {
2021-09-03 16:41:13 +05:30
mutatedResource := string ( yamlEncodedResource ) + string ( "\n---" )
if len ( strings . TrimSpace ( mutatedResource ) ) > 0 {
2022-10-19 22:09:15 +05:30
if ! c . Stdin {
fmt . Printf ( "\nmutate policy %s applied to %s:" , c . Policy . GetName ( ) , resPath )
2021-09-03 12:32:12 +05:30
}
2021-10-01 17:52:23 +05:30
fmt . Printf ( "\n" + mutatedResource + "\n" )
2021-09-03 12:32:12 +05:30
}
2021-09-03 16:41:13 +05:30
} else {
2022-10-19 22:09:15 +05:30
err := PrintMutatedOutput ( c . MutateLogPath , c . MutateLogPathIsDir , string ( yamlEncodedResource ) , c . Resource . GetName ( ) + "-mutated" )
2021-09-03 16:41:13 +05:30
if err != nil {
return sanitizederror . NewWithError ( "failed to print mutated result" , err )
}
fmt . Printf ( "\n\nMutation:\nMutation has been applied successfully. Check the files." )
}
}
return nil
}
2023-07-03 15:22:05 +02:00
func CheckVariableForPolicy ( valuesMap map [ string ] map [ string ] values . Resource , globalValMap map [ string ] string , policyName string , resourceName string , resourceKind string , variables map [ string ] string , kindOnwhichPolicyIsApplied map [ string ] struct { } , variable string ) ( map [ string ] interface { } , error ) {
2021-09-03 16:41:13 +05:30
// get values from file for this policy resource combination
2022-05-07 21:30:11 +01:00
thisPolicyResourceValues := make ( map [ string ] interface { } )
2023-07-03 15:22:05 +02:00
if len ( valuesMap [ policyName ] ) != 0 && ! datautils . DeepEqual ( valuesMap [ policyName ] [ resourceName ] , values . Resource { } ) {
2021-09-03 16:41:13 +05:30
thisPolicyResourceValues = valuesMap [ policyName ] [ resourceName ] . Values
}
2021-09-20 22:16:57 +05:30
2021-09-03 16:41:13 +05:30
for k , v := range variables {
thisPolicyResourceValues [ k ] = v
}
2021-09-20 22:16:57 +05:30
if thisPolicyResourceValues == nil && len ( globalValMap ) > 0 {
2022-05-07 21:30:11 +01:00
thisPolicyResourceValues = make ( map [ string ] interface { } )
2021-09-20 22:16:57 +05:30
}
for k , v := range globalValMap {
if _ , ok := thisPolicyResourceValues [ k ] ; ! ok {
thisPolicyResourceValues [ k ] = v
}
}
2021-09-03 16:41:13 +05:30
// skipping the variable check for non matching kind
if _ , ok := kindOnwhichPolicyIsApplied [ resourceKind ] ; ok {
2023-01-30 16:30:47 +01:00
if len ( variable ) > 0 && len ( thisPolicyResourceValues ) == 0 && store . HasPolicies ( ) {
2021-09-03 16:41:13 +05:30
return thisPolicyResourceValues , sanitizederror . NewWithError ( fmt . Sprintf ( "policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag" , policyName , resourceName ) , nil )
}
}
return thisPolicyResourceValues , nil
}
2023-07-03 15:22:05 +02:00
func GetKindsFromPolicy ( policy kyvernov1 . PolicyInterface , subresources [ ] values . Subresource , dClient dclient . Interface ) map [ string ] struct { } {
2022-05-17 08:19:03 +02:00
kindOnwhichPolicyIsApplied := make ( map [ string ] struct { } )
2022-03-28 16:01:27 +02:00
for _ , rule := range autogen . ComputeRules ( policy ) {
2021-09-03 16:41:13 +05:30
for _ , kind := range rule . MatchResources . ResourceDescription . Kinds {
2022-12-09 22:15:23 +05:30
k , err := getKind ( kind , subresources , dClient )
if err != nil {
fmt . Printf ( "Error: %s" , err . Error ( ) )
continue
}
kindOnwhichPolicyIsApplied [ k ] = struct { } { }
2021-09-03 16:41:13 +05:30
}
for _ , kind := range rule . ExcludeResources . ResourceDescription . Kinds {
2022-12-09 22:15:23 +05:30
k , err := getKind ( kind , subresources , dClient )
if err != nil {
fmt . Printf ( "Error: %s" , err . Error ( ) )
continue
}
kindOnwhichPolicyIsApplied [ k ] = struct { } { }
2021-09-03 16:41:13 +05:30
}
}
return kindOnwhichPolicyIsApplied
}
2021-10-01 14:16:33 +05:30
2023-07-03 15:22:05 +02:00
func getKind ( kind string , subresources [ ] values . Subresource , dClient dclient . Interface ) ( string , error ) {
2023-03-22 17:04:32 +01:00
group , version , kind , subresource := kubeutils . ParseKindSelector ( kind )
if subresource == "" {
return kind , nil
}
if dClient == nil {
gv := schema . GroupVersion { Group : group , Version : version }
return getSubresourceKind ( gv . String ( ) , kind , subresource , subresources )
}
gvrss , err := dClient . Discovery ( ) . FindResources ( group , version , kind , subresource )
if err != nil {
return kind , err
}
if len ( gvrss ) != 1 {
return kind , fmt . Errorf ( "no unique match for kind %s" , kind )
}
for _ , api := range gvrss {
return api . Kind , nil
2022-12-09 22:15:23 +05:30
}
2023-03-22 17:04:32 +01:00
return kind , nil
2022-12-09 22:15:23 +05:30
}
2023-07-03 15:22:05 +02:00
func getSubresourceKind ( groupVersion , parentKind , subresourceName string , subresources [ ] values . Subresource ) ( string , error ) {
2022-12-09 22:15:23 +05:30
for _ , subresource := range subresources {
parentResourceGroupVersion := metav1 . GroupVersion {
Group : subresource . ParentResource . Group ,
Version : subresource . ParentResource . Version ,
} . String ( )
if groupVersion == "" || kubeutils . GroupVersionMatches ( groupVersion , parentResourceGroupVersion ) {
if parentKind == subresource . ParentResource . Kind {
if strings . ToLower ( subresourceName ) == strings . Split ( subresource . APIResource . Name , "/" ) [ 1 ] {
return subresource . APIResource . Kind , nil
}
}
}
}
return "" , sanitizederror . NewWithError ( fmt . Sprintf ( "subresource %s not found for parent resource %s" , subresourceName , parentKind ) , nil )
}
2022-08-24 15:08:24 +02:00
// GetResourceFromPath - get patchedResource and generatedResource from given path
2022-05-25 19:56:22 +05:30
func GetResourceFromPath ( fs billy . Filesystem , path string , isGit bool , policyResourcePath string , resourceType string ) ( unstructured . Unstructured , error ) {
var resourceBytes [ ] byte
var resource unstructured . Unstructured
2021-10-01 14:16:33 +05:30
var err error
if isGit {
if len ( path ) > 0 {
2022-05-09 18:55:35 +02:00
filep , fileErr := fs . Open ( filepath . Join ( policyResourcePath , path ) )
if fileErr != nil {
2022-05-25 19:56:22 +05:30
fmt . Printf ( "Unable to open %s file: %s. \nerror: %s" , resourceType , path , err )
2021-10-01 14:16:33 +05:30
}
2022-09-30 15:25:19 +08:00
resourceBytes , err = io . ReadAll ( filep )
2021-10-01 14:16:33 +05:30
}
} else {
2022-05-25 19:56:22 +05:30
resourceBytes , err = getFileBytes ( path )
}
if err != nil {
fmt . Printf ( "\n----------------------------------------------------------------------\nfailed to load %s: %s. \nerror: %s\n----------------------------------------------------------------------\n" , resourceType , path , err )
return resource , err
2021-10-01 14:16:33 +05:30
}
2021-10-01 17:52:23 +05:30
2022-05-25 19:56:22 +05:30
resource , err = GetPatchedAndGeneratedResource ( resourceBytes )
2021-10-01 14:16:33 +05:30
if err != nil {
2022-05-25 19:56:22 +05:30
return resource , err
2021-10-01 14:16:33 +05:30
}
2021-10-01 17:52:23 +05:30
2022-05-25 19:56:22 +05:30
return resource , nil
}
// initializeMockController initializes a basic Generate Controller with a fake dynamic client.
func initializeMockController ( objects [ ] runtime . Object ) ( * generate . GenerateController , error ) {
2022-08-02 07:54:02 -07:00
client , err := dclient . NewFakeClient ( runtime . NewScheme ( ) , nil , objects ... )
2021-10-01 14:16:33 +05:30
if err != nil {
2022-05-25 19:56:22 +05:30
fmt . Printf ( "Failed to mock dynamic client" )
return nil , err
}
client . SetDiscovery ( dclient . NewFakeDiscoveryClient ( nil ) )
2023-04-13 13:29:40 +02:00
cfg := config . NewDefaultConfiguration ( false )
2023-02-03 06:01:11 +01:00
c := generate . NewGenerateControllerWithOnlyClient ( client , engine . NewEngine (
2023-04-13 13:29:40 +02:00
cfg ,
2023-04-04 17:07:43 +02:00
config . NewDefaultMetricsConfiguration ( ) ,
2023-04-13 13:29:40 +02:00
jmespath . New ( cfg ) ,
2023-06-10 11:20:34 +02:00
adapters . Client ( client ) ,
2023-02-08 06:55:03 +01:00
nil ,
2023-02-08 14:19:56 +01:00
store . ContextLoaderFactory ( nil ) ,
2023-02-06 06:49:47 +01:00
nil ,
2023-06-02 14:18:10 +02:00
"" ,
2023-02-03 06:01:11 +01:00
) )
2022-05-25 19:56:22 +05:30
return c , nil
}
// handleGeneratePolicy returns a new RuleResponse with the Kyverno generated resource configuration by applying the generate rule.
2023-01-30 12:41:09 +01:00
func handleGeneratePolicy ( generateResponse * engineapi . EngineResponse , policyContext engine . PolicyContext , ruleToCloneSourceResource map [ string ] string ) ( [ ] engineapi . RuleResponse , error ) {
2022-12-02 09:14:23 +01:00
resource := policyContext . NewResource ( )
objects := [ ] runtime . Object { & resource }
2022-08-24 15:08:24 +02:00
resources := [ ] * unstructured . Unstructured { }
2022-05-25 19:56:22 +05:30
for _ , rule := range generateResponse . PolicyResponse . Rules {
2023-04-05 12:35:38 +02:00
if path , ok := ruleToCloneSourceResource [ rule . Name ( ) ] ; ok {
2022-05-25 19:56:22 +05:30
resourceBytes , err := getFileBytes ( path )
if err != nil {
fmt . Printf ( "failed to get resource bytes\n" )
} else {
resources , err = GetResource ( resourceBytes )
if err != nil {
fmt . Printf ( "failed to convert resource bytes to unstructured format\n" )
}
}
}
}
for _ , res := range resources {
objects = append ( objects , res )
}
c , err := initializeMockController ( objects )
if err != nil {
fmt . Println ( "error at controller" )
return nil , err
}
gr := kyvernov1beta1 . UpdateRequest {
Spec : kyvernov1beta1 . UpdateRequestSpec {
Type : kyvernov1beta1 . Generate ,
2023-05-03 07:05:01 +02:00
Policy : generateResponse . Policy ( ) . GetName ( ) ,
2022-05-25 19:56:22 +05:30
Resource : kyvernov1 . ResourceSpec {
2023-02-10 15:04:41 +01:00
Kind : generateResponse . Resource . GetKind ( ) ,
Namespace : generateResponse . Resource . GetNamespace ( ) ,
Name : generateResponse . Resource . GetName ( ) ,
APIVersion : generateResponse . Resource . GetAPIVersion ( ) ,
2022-05-25 19:56:22 +05:30
} ,
} ,
}
2023-01-30 12:41:09 +01:00
var newRuleResponse [ ] engineapi . RuleResponse
2022-05-25 19:56:22 +05:30
for _ , rule := range generateResponse . PolicyResponse . Rules {
2023-04-18 14:08:17 +02:00
genResource , err := c . ApplyGeneratePolicy ( log . V ( 2 ) , & policyContext , gr , [ ] string { rule . Name ( ) } )
2022-05-25 19:56:22 +05:30
if err != nil {
return nil , err
}
2023-06-06 18:07:07 +08:00
if genResource != nil {
unstrGenResource , err := c . GetUnstrResource ( genResource [ 0 ] )
if err != nil {
return nil , err
}
newRuleResponse = append ( newRuleResponse , * rule . WithGeneratedResource ( * unstrGenResource ) )
2022-05-25 19:56:22 +05:30
}
2021-10-01 14:16:33 +05:30
}
2021-10-01 17:52:23 +05:30
2022-05-25 19:56:22 +05:30
return newRuleResponse , nil
2021-10-01 14:16:33 +05:30
}
2022-04-12 09:30:49 +05:30
2022-05-17 08:19:03 +02:00
// GetUserInfoFromPath - get the request info as user info from a given path
2023-02-08 14:19:56 +01:00
func GetUserInfoFromPath ( fs billy . Filesystem , path string , isGit bool , policyResourcePath string ) ( kyvernov1beta1 . RequestInfo , error ) {
2022-05-17 13:12:43 +02:00
userInfo := & kyvernov1beta1 . RequestInfo { }
2022-04-12 09:30:49 +05:30
if isGit {
filep , err := fs . Open ( filepath . Join ( policyResourcePath , path ) )
if err != nil {
fmt . Printf ( "Unable to open userInfo file: %s. \nerror: %s" , path , err )
}
2022-09-30 15:25:19 +08:00
bytes , err := io . ReadAll ( filep )
2022-04-12 09:30:49 +05:30
if err != nil {
fmt . Printf ( "Error: failed to read file %s: %v" , filep . Name ( ) , err . Error ( ) )
}
userInfoBytes , err := yaml . ToJSON ( bytes )
if err != nil {
fmt . Printf ( "failed to convert to JSON: %v" , err )
}
if err := json . Unmarshal ( userInfoBytes , userInfo ) ; err != nil {
fmt . Printf ( "failed to decode yaml: %v" , err )
}
} else {
var errors [ ] error
2022-09-30 15:25:19 +08:00
pathname := filepath . Clean ( filepath . Join ( policyResourcePath , path ) )
bytes , err := os . ReadFile ( pathname )
2022-04-12 09:30:49 +05:30
if err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "unable to read yaml" , err ) )
}
userInfoBytes , err := yaml . ToJSON ( bytes )
if err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "failed to convert json" , err ) )
}
if err := json . Unmarshal ( userInfoBytes , userInfo ) ; err != nil {
errors = append ( errors , sanitizederror . NewWithError ( "failed to decode yaml" , err ) )
}
2023-04-18 14:08:17 +02:00
if len ( errors ) > 0 && log . V ( 1 ) . Enabled ( ) {
2022-04-12 09:30:49 +05:30
fmt . Printf ( "ignoring errors: \n" )
for _ , e := range errors {
fmt . Printf ( " %v \n" , e . Error ( ) )
}
}
}
2023-02-08 14:19:56 +01:00
return * userInfo , nil
2022-04-12 09:30:49 +05:30
}
2022-12-02 20:03:04 +05:30
func IsGitSourcePath ( policyPaths [ ] string ) bool {
return strings . Contains ( policyPaths [ 0 ] , "https://" )
}
func GetGitBranchOrPolicyPaths ( gitBranch , repoURL string , policyPaths [ ] string ) ( string , string ) {
var gitPathToYamls string
if gitBranch == "" {
gitPathToYamls = "/"
if string ( policyPaths [ 0 ] [ len ( policyPaths [ 0 ] ) - 1 ] ) == "/" {
gitBranch = strings . ReplaceAll ( policyPaths [ 0 ] , repoURL + "/" , "" )
} else {
gitBranch = strings . ReplaceAll ( policyPaths [ 0 ] , repoURL , "" )
}
if gitBranch == "" {
gitBranch = "main"
} else if string ( gitBranch [ 0 ] ) == "/" {
gitBranch = gitBranch [ 1 : ]
}
return gitBranch , gitPathToYamls
}
if string ( policyPaths [ 0 ] [ len ( policyPaths [ 0 ] ) - 1 ] ) == "/" {
gitPathToYamls = strings . ReplaceAll ( policyPaths [ 0 ] , repoURL + "/" , "/" )
} else {
gitPathToYamls = strings . ReplaceAll ( policyPaths [ 0 ] , repoURL , "/" )
}
return gitBranch , gitPathToYamls
}