github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/agent/mcorpc/authz_actionpolicy_test.go (about)

     1  // Copyright (c) 2020-2021, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package mcorpc
     6  
     7  import (
     8  	"bytes"
     9  
    10  	"github.com/choria-io/go-choria/config"
    11  	imock "github.com/choria-io/go-choria/inter/imocks"
    12  	"github.com/golang/mock/gomock"
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  var _ = Describe("ActionPolicy", func() {
    19  	var (
    20  		authz     *actionPolicy
    21  		pol       *actionPolicyPolicy
    22  		logger    *logrus.Entry
    23  		mockctl   *gomock.Controller
    24  		fw        *imock.MockFramework
    25  		cfg       *config.Config
    26  		logbuffer *bytes.Buffer
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		logbuffer = &bytes.Buffer{}
    31  		logger = logrus.NewEntry(logrus.New())
    32  		logger.Logger.Out = logbuffer
    33  		pol = &actionPolicyPolicy{log: logger}
    34  
    35  		mockctl = gomock.NewController(GinkgoT())
    36  		fw, cfg = imock.NewFrameworkForTests(mockctl, GinkgoWriter)
    37  		cfg.ClassesFile = "testdata/classes.txt"
    38  		cfg.FactSourceFile = "testdata/facts.json"
    39  		cfg.DisableSecurityProviderVerify = true
    40  
    41  		authz = &actionPolicy{
    42  			cfg:     cfg,
    43  			log:     logger,
    44  			matcher: pol,
    45  			groups:  make(map[string][]string),
    46  			req: &Request{
    47  				Agent:    "ginkgo",
    48  				Action:   "test",
    49  				CallerID: "choria=ginkgo.mcollective",
    50  			},
    51  			agent: &Agent{
    52  				Log:    logger,
    53  				Config: cfg,
    54  				Choria: fw,
    55  			},
    56  		}
    57  	})
    58  
    59  	AfterEach(func() {
    60  		mockctl.Finish()
    61  	})
    62  
    63  	Describe("parseGroupFile", func() {
    64  		It("Should correctly parse the file", func() {
    65  			err := authz.parseGroupFile("testdata/policies/groups")
    66  			Expect(err).ToNot(HaveOccurred())
    67  			Expect(authz.groups).To(Equal(map[string][]string{
    68  				"sysadmin":     {"cert=sa1", "cert=sa2", "rspec_caller"},
    69  				"app_admin":    {"cert=aa1", "cert=aa2"},
    70  				"single_group": {"rspec_caller"},
    71  			}))
    72  		})
    73  	})
    74  
    75  	Describe("evaluatePolicy", func() {
    76  		It("Should allow when default allow is set", func() {
    77  			matched, reason, err := authz.evaluatePolicy("testdata/policies/default_allow")
    78  			Expect(err).ToNot(HaveOccurred())
    79  			Expect(reason).To(Equal(""))
    80  			Expect(matched).To(BeTrue())
    81  		})
    82  
    83  		It("Should deny when default deny is set", func() {
    84  			matched, reason, err := authz.evaluatePolicy("testdata/policies/default_deny")
    85  			Expect(err).ToNot(HaveOccurred())
    86  			Expect(reason).To(Equal("Denying based on default policy in default_deny"))
    87  			Expect(matched).To(BeFalse())
    88  		})
    89  
    90  		Describe("example1", func() {
    91  			It("Should allow all requests", func() {
    92  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example1")
    93  				Expect(err).ToNot(HaveOccurred())
    94  				Expect(reason).To(Equal(""))
    95  				Expect(matched).To(BeTrue())
    96  			})
    97  		})
    98  
    99  		Describe("example2", func() {
   100  			It("Should allow the right caller", func() {
   101  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example2")
   102  				Expect(err).ToNot(HaveOccurred())
   103  				Expect(reason).To(Equal(""))
   104  				Expect(matched).To(BeTrue())
   105  			})
   106  
   107  			It("Should deny the wrong caller", func() {
   108  				authz.req.CallerID = "other"
   109  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example2")
   110  				Expect(err).ToNot(HaveOccurred())
   111  				Expect(reason).To(Equal("Denying based on default policy in example2"))
   112  				Expect(matched).To(BeFalse())
   113  			})
   114  
   115  			It("Should match the regex caller", func() {
   116  				authz.req.CallerID = "up=bob"
   117  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example2")
   118  				Expect(err).ToNot(HaveOccurred())
   119  				Expect(reason).To(Equal(""))
   120  				Expect(matched).To(BeTrue())
   121  			})
   122  		})
   123  
   124  		Describe("example3", func() {
   125  			It("Should allow requests to the matching agent", func() {
   126  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example3")
   127  				Expect(err).ToNot(HaveOccurred())
   128  				Expect(reason).To(Equal(""))
   129  				Expect(matched).To(BeTrue())
   130  			})
   131  
   132  			It("Should deny other requests", func() {
   133  				authz.req.Action = "other"
   134  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example3")
   135  				Expect(err).ToNot(HaveOccurred())
   136  				Expect(reason).To(Equal("Denying based on default policy in example3"))
   137  				Expect(matched).To(BeFalse())
   138  			})
   139  		})
   140  
   141  		Describe("example4", func() {
   142  			It("Should match correctly", func() {
   143  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   144  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example4")
   145  				Expect(err).ToNot(HaveOccurred())
   146  				Expect(reason).To(Equal(""))
   147  				Expect(matched).To(BeTrue())
   148  			})
   149  
   150  			It("Should deny correctly", func() {
   151  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   152  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example4")
   153  				Expect(err).ToNot(HaveOccurred())
   154  				Expect(reason).To(Equal("Denying based on default policy in example4"))
   155  				Expect(matched).To(BeFalse())
   156  			})
   157  		})
   158  
   159  		Describe("example5", func() {
   160  			It("Should match correctly", func() {
   161  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example5")
   162  				Expect(err).ToNot(HaveOccurred())
   163  				Expect(reason).To(Equal(""))
   164  				Expect(matched).To(BeTrue())
   165  			})
   166  
   167  			It("Should deny correctly", func() {
   168  				cfg.ClassesFile = "testdata/classes_2.txt"
   169  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example5")
   170  				Expect(err).ToNot(HaveOccurred())
   171  				Expect(reason).To(Equal("Denying based on default policy in example5"))
   172  				Expect(matched).To(BeFalse())
   173  			})
   174  		})
   175  
   176  		Describe("example6", func() {
   177  			It("Should match correctly", func() {
   178  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example6")
   179  				Expect(err).ToNot(HaveOccurred())
   180  				Expect(reason).To(Equal(""))
   181  				Expect(matched).To(BeTrue())
   182  			})
   183  
   184  			It("Should deny correctly", func() {
   185  				authz.req.Action = "other"
   186  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example6")
   187  				Expect(err).ToNot(HaveOccurred())
   188  				Expect(reason).To(Equal("Denying based on default policy in example6"))
   189  				Expect(matched).To(BeFalse())
   190  
   191  				authz.req.CallerID = "other"
   192  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example6")
   193  				Expect(err).ToNot(HaveOccurred())
   194  				Expect(reason).To(Equal("Denying based on default policy in example6"))
   195  				Expect(matched).To(BeFalse())
   196  			})
   197  		})
   198  
   199  		Describe("example7", func() {
   200  			It("Should match correctly", func() {
   201  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   202  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example7")
   203  				Expect(err).ToNot(HaveOccurred())
   204  				Expect(reason).To(Equal(""))
   205  				Expect(matched).To(BeTrue())
   206  			})
   207  
   208  			It("Should deny correctly", func() {
   209  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   210  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example7")
   211  				Expect(err).ToNot(HaveOccurred())
   212  				Expect(reason).To(Equal("Denying based on default policy in example7"))
   213  				Expect(matched).To(BeFalse())
   214  
   215  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   216  				authz.req.CallerID = "other"
   217  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example7")
   218  				Expect(err).ToNot(HaveOccurred())
   219  				Expect(reason).To(Equal("Denying based on default policy in example7"))
   220  				Expect(matched).To(BeFalse())
   221  			})
   222  		})
   223  
   224  		Describe("example8", func() {
   225  			It("Should match correctly", func() {
   226  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example8")
   227  				Expect(err).ToNot(HaveOccurred())
   228  				Expect(reason).To(Equal(""))
   229  				Expect(matched).To(BeTrue())
   230  			})
   231  
   232  			It("Should deny correctly", func() {
   233  				cfg.ClassesFile = "testdata/classes_2.txt"
   234  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example8")
   235  				Expect(err).ToNot(HaveOccurred())
   236  				Expect(reason).To(Equal("Denying based on default policy in example8"))
   237  				Expect(matched).To(BeFalse())
   238  
   239  				cfg.ClassesFile = "testdata/missing"
   240  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example8")
   241  				Expect(err).ToNot(HaveOccurred())
   242  				Expect(reason).To(Equal("Denying based on default policy in example8"))
   243  				Expect(matched).To(BeFalse())
   244  
   245  				cfg.ClassesFile = "testdata/classes.txt"
   246  				authz.req.CallerID = "other"
   247  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example8")
   248  				Expect(err).ToNot(HaveOccurred())
   249  				Expect(reason).To(Equal("Denying based on default policy in example8"))
   250  				Expect(matched).To(BeFalse())
   251  			})
   252  		})
   253  
   254  		Describe("example9", func() {
   255  			It("Should match correctly", func() {
   256  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   257  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example9")
   258  				Expect(err).ToNot(HaveOccurred())
   259  				Expect(reason).To(Equal(""))
   260  				Expect(matched).To(BeTrue())
   261  			})
   262  
   263  			It("Should deny correctly", func() {
   264  				authz.req.CallerID = "other"
   265  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   266  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example9")
   267  				Expect(err).ToNot(HaveOccurred())
   268  				Expect(reason).To(Equal("Denying based on default policy in example9"))
   269  				Expect(matched).To(BeFalse())
   270  
   271  				authz.req.CallerID = "choria=ginkgo.mcollective"
   272  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   273  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example9")
   274  				Expect(err).ToNot(HaveOccurred())
   275  				Expect(reason).To(Equal("Denying based on default policy in example9"))
   276  				Expect(matched).To(BeFalse())
   277  
   278  				authz.req.CallerID = "choria=ginkgo.mcollective"
   279  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   280  				authz.req.Action = "other"
   281  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example9")
   282  				Expect(err).ToNot(HaveOccurred())
   283  				Expect(reason).To(Equal("Denying based on default policy in example9"))
   284  				Expect(matched).To(BeFalse())
   285  
   286  			})
   287  		})
   288  
   289  		Describe("example10", func() {
   290  			It("Should match correctly", func() {
   291  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example10")
   292  				Expect(err).ToNot(HaveOccurred())
   293  				Expect(reason).To(Equal(""))
   294  				Expect(matched).To(BeTrue())
   295  			})
   296  
   297  			It("Should deny correctly", func() {
   298  				authz.req.CallerID = "other"
   299  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example10")
   300  				Expect(err).ToNot(HaveOccurred())
   301  				Expect(reason).To(Equal("Denying based on default policy in example10"))
   302  				Expect(matched).To(BeFalse())
   303  
   304  				authz.req.CallerID = "choria=ginkgo.mcollective"
   305  				authz.req.Action = "other"
   306  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example10")
   307  				Expect(err).ToNot(HaveOccurred())
   308  				Expect(reason).To(Equal("Denying based on default policy in example10"))
   309  				Expect(matched).To(BeFalse())
   310  
   311  				authz.req.Action = "test"
   312  				cfg.ClassesFile = "testdata/classes_2.txt"
   313  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example10")
   314  				Expect(err).ToNot(HaveOccurred())
   315  				Expect(reason).To(Equal("Denying based on default policy in example10"))
   316  				Expect(matched).To(BeFalse())
   317  			})
   318  		})
   319  
   320  		Describe("example11", func() {
   321  			It("Should match correctly", func() {
   322  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   323  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example11")
   324  				Expect(err).ToNot(HaveOccurred())
   325  				Expect(reason).To(Equal(""))
   326  				Expect(matched).To(BeTrue())
   327  			})
   328  
   329  			It("Should deny correctly", func() {
   330  				authz.req.CallerID = "other"
   331  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example11")
   332  				Expect(err).ToNot(HaveOccurred())
   333  				Expect(reason).To(Equal("Denying based on default policy in example11"))
   334  				Expect(matched).To(BeFalse())
   335  
   336  				authz.req.CallerID = "choria=ginkgo.mcollective"
   337  				authz.req.Action = "other"
   338  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example11")
   339  				Expect(err).ToNot(HaveOccurred())
   340  				Expect(reason).To(Equal("Denying based on default policy in example11"))
   341  				Expect(matched).To(BeFalse())
   342  
   343  				authz.req.Action = "test"
   344  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   345  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example11")
   346  				Expect(err).ToNot(HaveOccurred())
   347  				Expect(reason).To(Equal("Denying based on default policy in example11"))
   348  				Expect(matched).To(BeFalse())
   349  
   350  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   351  				cfg.ClassesFile = "testdata/classes_2.txt"
   352  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example11")
   353  				Expect(err).ToNot(HaveOccurred())
   354  				Expect(reason).To(Equal("Denying based on default policy in example11"))
   355  				Expect(matched).To(BeFalse())
   356  			})
   357  		})
   358  
   359  		Describe("example12", func() {
   360  			It("Should fail due to compound statement", func() {
   361  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example12")
   362  				Expect(logbuffer.Bytes()).To(ContainSubstring("Compound policy statements are not supported"))
   363  				Expect(err).ToNot(HaveOccurred())
   364  				Expect(reason).To(Equal("Denying based on default policy in example12"))
   365  				Expect(matched).To(BeFalse())
   366  			})
   367  		})
   368  
   369  		Describe("example13", func() {
   370  			It("Should fail due to compound statement", func() {
   371  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example13")
   372  				Expect(logbuffer.Bytes()).To(ContainSubstring("Compound policy statements are not supported"))
   373  				Expect(err).ToNot(HaveOccurred())
   374  				Expect(reason).To(Equal("Denying based on default policy in example13"))
   375  				Expect(matched).To(BeFalse())
   376  			})
   377  		})
   378  
   379  		Describe("example14", func() {
   380  			It("Should fail due to compound statement", func() {
   381  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example14")
   382  				Expect(logbuffer.Bytes()).To(ContainSubstring("Compound policy statements are not supported"))
   383  				Expect(err).ToNot(HaveOccurred())
   384  				Expect(reason).To(Equal("Denying based on default policy in example14"))
   385  				Expect(matched).To(BeFalse())
   386  			})
   387  		})
   388  
   389  		Describe("example15", func() {
   390  			It("Should match policy 1", func() {
   391  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example15")
   392  				Expect(err).ToNot(HaveOccurred())
   393  				Expect(reason).To(Equal(""))
   394  				Expect(matched).To(BeTrue())
   395  
   396  				authz.req.CallerID = "other"
   397  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example15")
   398  				Expect(err).ToNot(HaveOccurred())
   399  				Expect(reason).To(Equal("Denying based on default policy in example15"))
   400  				Expect(matched).To(BeFalse())
   401  			})
   402  
   403  			It("Should match policy 2", func() {
   404  				authz.req.CallerID = "choria=two.mcollective"
   405  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   406  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example15")
   407  				Expect(err).ToNot(HaveOccurred())
   408  				Expect(reason).To(Equal(""))
   409  				Expect(matched).To(BeTrue())
   410  
   411  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   412  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example15")
   413  				Expect(err).ToNot(HaveOccurred())
   414  				Expect(matched).To(BeFalse())
   415  				Expect(reason).To(Equal("Denying based on default policy in example15"))
   416  			})
   417  
   418  			It("Should match policy 3", func() {
   419  				authz.req.CallerID = "choria=three.mcollective"
   420  				cfg.FactSourceFile = "testdata/foo_bar_facts.json"
   421  
   422  				for _, act := range []string{"enable", "disable", "status"} {
   423  					authz.req.Action = act
   424  					matched, reason, err := authz.evaluatePolicy("testdata/policies/example15")
   425  					Expect(err).ToNot(HaveOccurred())
   426  					Expect(reason).To(Equal(""))
   427  					Expect(matched).To(BeTrue())
   428  				}
   429  
   430  				authz.req.Action = "other"
   431  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example15")
   432  				Expect(err).ToNot(HaveOccurred())
   433  				Expect(reason).To(Equal("Denying based on default policy in example15"))
   434  				Expect(matched).To(BeFalse())
   435  
   436  				authz.req.Action = "status"
   437  				cfg.FactSourceFile = "testdata/foo_baz_facts.json"
   438  				matched, reason, err = authz.evaluatePolicy("testdata/policies/example15")
   439  				Expect(err).ToNot(HaveOccurred())
   440  				Expect(reason).To(Equal("Denying based on default policy in example15"))
   441  				Expect(matched).To(BeFalse())
   442  			})
   443  
   444  			It("Should match policy 4", func() {
   445  				authz.req.CallerID = "choria=four.mcollective"
   446  				authz.req.Action = "restart"
   447  
   448  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example15")
   449  				Expect(logbuffer.Bytes()).To(ContainSubstring("Compound policy statements are not supported"))
   450  				Expect(err).ToNot(HaveOccurred())
   451  				Expect(reason).To(Equal("Denying based on default policy in example15"))
   452  				Expect(matched).To(BeFalse())
   453  			})
   454  		})
   455  
   456  		Describe("example16", func() {
   457  			It("Should match correctly", func() {
   458  				for _, c := range []string{"uid=500", "uid=600", "uid=700"} {
   459  					authz.req.CallerID = c
   460  					matched, reason, err := authz.evaluatePolicy("testdata/policies/example16")
   461  					Expect(err).ToNot(HaveOccurred())
   462  					Expect(reason).To(Equal(""))
   463  					Expect(matched).To(BeTrue())
   464  				}
   465  			})
   466  
   467  			It("Should deny correctly", func() {
   468  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example16")
   469  				Expect(err).ToNot(HaveOccurred())
   470  				Expect(reason).To(Equal("Denying based on default policy in example16"))
   471  				Expect(matched).To(BeFalse())
   472  			})
   473  		})
   474  
   475  		Describe("example17", func() {
   476  			It("Should match correctly", func() {
   477  				authz.parseGroupFile("testdata/policies/groups")
   478  				authz.req.CallerID = "cert=sa1"
   479  				matched, _, err := authz.evaluatePolicy("testdata/policies/example17")
   480  				Expect(err).ToNot(HaveOccurred())
   481  				Expect(matched).To(BeTrue())
   482  
   483  				authz.req.CallerID = "cert=aa1"
   484  				matched, _, err = authz.evaluatePolicy("testdata/policies/example17")
   485  				Expect(err).ToNot(HaveOccurred())
   486  				Expect(matched).To(BeTrue())
   487  			})
   488  
   489  			It("Should deny correctly", func() {
   490  				authz.parseGroupFile("testdata/policies/groups")
   491  				matched, reason, err := authz.evaluatePolicy("testdata/policies/example17")
   492  				Expect(err).ToNot(HaveOccurred())
   493  				Expect(reason).To(Equal("Denying based on default policy in example17"))
   494  				Expect(matched).To(BeFalse())
   495  			})
   496  		})
   497  	})
   498  })
   499  
   500  var _ = Describe("Policy", func() {
   501  	var (
   502  		pol       *actionPolicyPolicy
   503  		logger    *logrus.Entry
   504  		logbuffer *bytes.Buffer
   505  		cfg       *config.Config
   506  	)
   507  
   508  	BeforeEach(func() {
   509  		logbuffer = &bytes.Buffer{}
   510  		logger = logrus.NewEntry(logrus.New())
   511  		logger.Logger.Out = logbuffer
   512  		pol = &actionPolicyPolicy{log: logger, file: "/nonexisting"}
   513  
   514  		cfg = config.NewConfigForTests()
   515  		cfg.DisableSecurityProviderVerify = true
   516  	})
   517  
   518  	Describe("matchesFacts", func() {
   519  		It("Should correctly match empty policy", func() {
   520  			matched, err := pol.MatchesFacts(cfg, logger)
   521  			Expect(err).To(MatchError("empty fact policy found"))
   522  			Expect(matched).To(BeFalse())
   523  		})
   524  
   525  		It("Should correctly match *", func() {
   526  			pol.facts = "*"
   527  			matched, err := pol.MatchesFacts(cfg, logger)
   528  			Expect(err).ToNot(HaveOccurred())
   529  			Expect(matched).To(BeTrue())
   530  		})
   531  
   532  		It("Should correctly match compound filters", func() {
   533  			pol.facts = "this and that"
   534  			matched, err := pol.MatchesFacts(cfg, logger)
   535  			Expect(err).To(MatchError("compound statements are not supported"))
   536  			Expect(matched).To(BeFalse())
   537  		})
   538  
   539  		It("Should correctly catch invalid fact filters", func() {
   540  			pol.facts = "foo bar"
   541  			matched, err := pol.MatchesFacts(cfg, logger)
   542  			Expect(err).To(MatchError("invalid fact matcher: could not parse fact foo it does not appear to be in a valid format"))
   543  			Expect(matched).To(BeFalse())
   544  		})
   545  
   546  		It("Should correctly match facts", func() {
   547  			cfg.FactSourceFile = "testdata/facts.json"
   548  			pol.facts = "one=one"
   549  			matched, err := pol.MatchesFacts(cfg, logger)
   550  			Expect(err).ToNot(HaveOccurred())
   551  			Expect(matched).To(BeTrue())
   552  
   553  			pol.facts = "one=~/n/"
   554  			matched, err = pol.MatchesFacts(cfg, logger)
   555  			Expect(err).ToNot(HaveOccurred())
   556  			Expect(matched).To(BeTrue())
   557  		})
   558  	})
   559  
   560  	Describe("matchesClasses", func() {
   561  		It("Should correctly match empty policy", func() {
   562  			matched, err := pol.MatchesClasses("/tmp/classes", logger)
   563  			Expect(err).To(MatchError("empty classes policy found"))
   564  			Expect(matched).To(BeFalse())
   565  		})
   566  
   567  		It("Should correctly match empty classes files", func() {
   568  			pol.classes = "one"
   569  			matched, err := pol.MatchesClasses("", logger)
   570  			Expect(err).To(MatchError("do not know how to resolve classes"))
   571  			Expect(matched).To(BeFalse())
   572  		})
   573  
   574  		It("Should correctly match *", func() {
   575  			pol.classes = "*"
   576  			matched, err := pol.MatchesClasses("testdata/classes.txt", logger)
   577  			Expect(err).ToNot(HaveOccurred())
   578  			Expect(matched).To(BeTrue())
   579  		})
   580  
   581  		It("Should detect fact matches in classes field", func() {
   582  			pol.classes = "foo and bar"
   583  			matched, err := pol.MatchesClasses("testdata/classes.txt", logger)
   584  			Expect(err).To(MatchError("compound statements are not supported"))
   585  			Expect(matched).To(BeFalse())
   586  		})
   587  
   588  		It("Should match classes correctly", func() {
   589  			pol.classes = "one two three"
   590  			matched, err := pol.MatchesClasses("testdata/classes.txt", logger)
   591  			Expect(err).ToNot(HaveOccurred())
   592  			Expect(matched).To(BeTrue())
   593  
   594  			pol.classes = "one two four"
   595  			matched, err = pol.MatchesClasses("testdata/classes.txt", logger)
   596  			Expect(err).ToNot(HaveOccurred())
   597  			Expect(matched).To(BeFalse())
   598  		})
   599  	})
   600  
   601  	Describe("matchesAction", func() {
   602  		It("should correctly match empty policy", func() {
   603  			Expect(pol.MatchesAction("install")).To(BeFalse())
   604  		})
   605  
   606  		It("Should support * matches", func() {
   607  			pol.actions = "*"
   608  			Expect(pol.MatchesAction("install")).To(BeTrue())
   609  		})
   610  
   611  		It("Should match actions", func() {
   612  			pol.actions = "one two three"
   613  			Expect(pol.MatchesAction("install")).To(BeFalse())
   614  			Expect(pol.MatchesAction("one")).To(BeTrue())
   615  			Expect(pol.MatchesAction("two")).To(BeTrue())
   616  			Expect(pol.MatchesAction("three")).To(BeTrue())
   617  		})
   618  	})
   619  
   620  	Describe("matchesCallerID", func() {
   621  		It("Should correctly match empty policy", func() {
   622  			Expect(pol.MatchesCallerID("choria=bob")).To(BeFalse())
   623  		})
   624  
   625  		It("Should support * matches", func() {
   626  			pol.caller = "*"
   627  			Expect(pol.MatchesCallerID("choria=bob")).To(BeTrue())
   628  		})
   629  
   630  		It("Should match callers", func() {
   631  			pol.caller = "choria=bob choria=jill"
   632  			Expect(pol.MatchesCallerID("choria=bob")).To(BeTrue())
   633  			Expect(pol.MatchesCallerID("choria=jill")).To(BeTrue())
   634  			Expect(pol.MatchesCallerID("choria=jane")).To(BeFalse())
   635  		})
   636  
   637  		It("Should support regex policies", func() {
   638  			pol.caller = "choria=bob /^up=/ choria=jill"
   639  			Expect(pol.MatchesCallerID("choria=bob")).To(BeTrue())
   640  			Expect(pol.MatchesCallerID("up=foo")).To(BeTrue())
   641  			Expect(pol.MatchesCallerID("up=other")).To(BeTrue())
   642  			Expect(pol.MatchesCallerID("up^other")).To(BeFalse())
   643  			Expect(pol.MatchesCallerID("choria=jill")).To(BeTrue())
   644  
   645  			pol.caller = "choria=bob //"
   646  			Expect(pol.MatchesCallerID("up=foo")).To(BeFalse())
   647  			Expect(logbuffer.String()).To(ContainSubstring("Invalid CallerID matcher '//' found in policy file /nonexisting"))
   648  
   649  			pol.caller = "choria=bob /*/"
   650  			Expect(pol.MatchesCallerID("up=foo")).To(BeFalse())
   651  			Expect(logbuffer.String()).To(ContainSubstring("Could not compile regex found in CallerID '/*/' in policy file /nonexisting: error parsing regexp: missing argument to repetition operator: `*`"))
   652  
   653  		})
   654  	})
   655  
   656  	Describe("isCallerInGroups", func() {
   657  		It("Should match on known groups", func() {
   658  			groups := map[string][]string{
   659  				"sysadmin":     {"cert=sa1", "cert=sa2", "rspec_caller"},
   660  				"app_admin":    {"cert=aa1", "cert=aa2"},
   661  				"single_group": {"rspec_caller"},
   662  			}
   663  
   664  			pol.groups = groups
   665  			pol.caller = "app_admin sysadmin"
   666  			Expect(pol.isCallerInGroups("cert=sa1")).To(BeTrue())
   667  			Expect(pol.isCallerInGroups("cert=aa1")).To(BeTrue())
   668  			Expect(pol.isCallerInGroups("other")).To(BeFalse())
   669  		})
   670  	})
   671  
   672  	Describe("sCompound", func() {
   673  		It("should detect combound filters correctly", func() {
   674  			Expect(pol.IsCompound("one two")).To(BeFalse())
   675  			Expect(pol.IsCompound("country=mt os=linux")).To(BeFalse())
   676  			Expect(pol.IsCompound("this and that")).To(BeTrue())
   677  			Expect(pol.IsCompound("this or that")).To(BeTrue())
   678  			Expect(pol.IsCompound("this or not that")).To(BeTrue())
   679  		})
   680  	})
   681  })