Skip to content

Commit

Permalink
Allow setting policies on actions
Browse files Browse the repository at this point in the history
Policies is a new concept which let you allowing teams to do some
actions and reject member who are not part of those teams.

Current actions supported are `pull_request` and `ok_to_test` (more to
come in the future)

See the documentation attached to this PullRequest for more description
on how to use this feature.

Signed-off-by: Chmouel Boudjnah <[email protected]>
  • Loading branch information
chmouel committed Jun 15, 2023
1 parent 9f977db commit b3c3fba
Show file tree
Hide file tree
Showing 38 changed files with 1,105 additions and 268 deletions.
2 changes: 1 addition & 1 deletion .tekton/doc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ spec:
- name: source
steps:
- name: hugo-gen
image: registry.access.redhat.com/ubi9/python-311 # using this image since it has git and curl and python
image: registry.access.redhat.com/ubi9/python-311 # using this image since it has git and curl and python
workingDir: $(workspaces.source.path)
env:
- name: UPLOADER_PUBLIC_URL
Expand Down
14 changes: 14 additions & 0 deletions config/300-repositories.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@ spec:
description: Settings relative to the Repository
type: object
properties:
policy:
type: object
description: Set policy on actions allowing only some teams
properties:
ok_to_test:
type: array
items:
description: list of teams allowed to run /ok-to-test
type: string
pull_request:
type: array
items:
description: list of teams allowed to have ci run on pull/merge requests.
type: string
github_app_token_scope_repos:
type: array
items:
Expand Down
63 changes: 63 additions & 0 deletions docs/content/docs/guide/policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: Policy on actions
weight: 9
---
# Policy on Pipeline as Code actions

Pipelines as Code has the concepts of Policy to let you control an action allowed
to be executed by a set of users belonging to a Team on an Organisation as
defined on GitHub or other Git Providers (only GitHub and Gitea is supported at
the moment).

## List of actions supported

* `pull_request` - This action is triggering the CI on Pipelines as Code,
specifying a team will only allow the members of the team to trigger the CI
and will not allow other members regadless if they are Owners or Collaborators
of the repository or the Organization. The OWNERS file is still taken into
account and will as well allow the members of the OWNERS file to trigger the
CI.
* `ok_to_test` - This action will let a user belonging to the allowed team to
issue a `/ok-to-test` comment on a Pull Request to trigger the CI on
Pipelines as Code, this let running the CI on Pull Request contributed by a
non collaborator of the repository or the organisation. This apply to the
`/test` and `/retest` commands as well. This take precendence on the
`pull_request` action.

## Configuring the Policy on the Repository CR

To configure the Policy on the Repository CR you need to add the following to the setting of the Repository CR:

```yaml
apiVersion: "pipelinesascode.tekton.dev/v1alpha1"
kind: Repository
metadata:
name: repository1
spec:
url: "https://github.com/org/repo"
settings:
policy:
ok_to_test:
- ci-admins
pull_request:
- ci-users
```
Users in `ci-admins` team will be able to let other users run the CI on the pull
request and users in `ci-users` team will be able to run the CI on their own
pull request.

## Configuring teams on GitHub

You will need to configure the GitHub Apps on your organisation to use this
feature.

See the documentation on GitHub to configure the teams:

<https://docs.github.com/en/organizations/organizing-members-into-teams/about-teams>

## Configuring teams on Gitea

Teams on Gitea are configured on the Organization level. No documentation is
available but you can look at the GitHub documentation to get an idea of how to
configure it.
8 changes: 7 additions & 1 deletion pkg/apis/pipelinesascode/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type TaskInfos struct {

// RepositorySpec is the spec of a repo
type RepositorySpec struct {
ConcurrencyLimit *int `json:"concurrency_limit,omitempty"`
ConcurrencyLimit *int `json:"concurrency_limit,omitempty"` // move it to settings in further version of the spec
URL string `json:"url"`
GitProvider *GitProvider `json:"git_provider,omitempty"`
Incomings *[]Incoming `json:"incoming,omitempty"`
Expand All @@ -81,6 +81,12 @@ type RepositorySpec struct {
type Settings struct {
GithubAppTokenScopeRepos []string `json:"github_app_token_scope_repos,omitempty"`
PipelineRunProvenance string `json:"pipelinerun_provenance,omitempty"`
Policy *Policy `json:"policy,omitempty"`
}

type Policy struct {
OkToTest []string `json:"ok_to_test,omitempty"`
PullRequest []string `json:"pull_request,omitempty"`
}

type Params struct {
Expand Down
14 changes: 14 additions & 0 deletions pkg/params/info/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type Event struct {
// TriggerTarget stable field across providers, ie: on Gitlab, Github and
// others it would be always be pull_request we can rely on to know if it's
// a push or a pull_request
// we need to merge this with the TriggerType type by doing a review of
// every instance using this and adapt it.
TriggerTarget string

// Target PipelineRun, the target PipelineRun user request. Used in incoming webhook
Expand Down Expand Up @@ -89,3 +91,15 @@ func NewEvent() *Event {
Request: &Request{},
}
}

type TriggerType string

const (
TriggerTypeOkToTest TriggerType = "ok-to-test"
TriggerTypeRetest TriggerType = "retest"
TriggerTypePush TriggerType = "push"
TriggerTypePullRequest TriggerType = "pull_request"
TriggerTypeCancel TriggerType = "cancel"
TriggerTypeCheckSuiteRerequested TriggerType = "check-suite-rerequested"
TriggerTypeCheckRunRerequested TriggerType = "check-run-rerequested"
)
2 changes: 1 addition & 1 deletion pkg/pipelineascode/match.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ is that what you want? make sure you use -n when generating the secret, eg: echo

// Set the client, we should error out if there is a problem with
// token or secret or we won't be able to do much.
err = p.vcx.SetClient(ctx, p.run, p.event)
err = p.vcx.SetClient(ctx, p.run, p.event, repo.Spec.Settings)
if err != nil {
return repo, err
}
Expand Down
60 changes: 60 additions & 0 deletions pkg/policy/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package policy

import (
"context"
"fmt"

"github.com/openshift-pipelines/pipelines-as-code/pkg/apis/pipelinesascode/v1alpha1"
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
"github.com/openshift-pipelines/pipelines-as-code/pkg/provider"
"go.uber.org/zap"
)

type Result int

const (
ResultNotSet Result = 0
ResultAllowed Result = 1
ResultDisallowed Result = 2
)

type Policy struct {
Settings *v1alpha1.Settings
Event *info.Event
VCX provider.Interface
Logger *zap.SugaredLogger
}

func (p *Policy) IsAllowed(ctx context.Context, tType info.TriggerType) (Result, error) {
if p.Settings == nil || p.Settings.Policy == nil {
return ResultNotSet, nil
}

var sType []string
switch tType {
// NOTE: This make /retest /ok-to-test /test bound to the same policy, which is fine from a security standpoint but maybe we want to refind
case info.TriggerTypeOkToTest, info.TriggerTypeRetest:
sType = p.Settings.Policy.OkToTest
case info.TriggerTypePullRequest:
sType = p.Settings.Policy.PullRequest
// NOTE: not supported yet, will imp if it gets requested and reasonable to implement
case info.TriggerTypePush, info.TriggerTypeCancel, info.TriggerTypeCheckSuiteRerequested, info.TriggerTypeCheckRunRerequested:
return ResultNotSet, nil
default:
return ResultNotSet, nil
}

if len(sType) == 0 {
return ResultNotSet, nil
}

allowed, reason := p.VCX.CheckPolicyAllowing(ctx, p.Event, sType)
reasonMsg := fmt.Sprintf("policy check: %s, %s", string(tType), reason)
if reason != "" {
p.Logger.Info(reasonMsg)
}
if allowed {
return ResultAllowed, nil
}
return ResultDisallowed, fmt.Errorf(reasonMsg)
}
Loading

0 comments on commit b3c3fba

Please sign in to comment.