Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/policy-bot.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ sessions:
# # POLICYBOT_OPTIONS_FORCE_SHARED_POLICY environment variable.
# force_shared_policy: false
#
# # The shared organization to use with shared_repository.
# # If unset, defaults to using the same organization as the organization which contains the pull request repository.
# shared_organization: kouzoh
#
# # The installation ID of the app installation on the shared organization.
# shared_organization_installation_id: 81498622
#
# # The name of an organization repository to look in for a shared policy if
# # a repository does not define a policy file. Can also be set by the
# # POLICYBOT_OPTIONS_SHARED_REPOSITORY environment variable. Explicitly set
Expand All @@ -128,6 +135,9 @@ sessions:
# # Can also be set by the POLICYBOT_OPTIONS_SHARED_POLICY_PATH environment variable.
# shared_policy_path: policy.yml
#
# # Whether the status check should be dry-run only (log to console only, without writing to GitHub API).
# status_check_dry_run_only: false
#
# # The context prefix for status checks created by the bot. Can also be set by the
# # POLICYBOT_OPTIONS_STATUS_CHECK_CONTEXT environment variable.
# status_check_context: policy-bot
Expand Down
7 changes: 6 additions & 1 deletion server/handler/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ type Base struct {
}

// PostStatus posts a GitHub commit status with consistent logging.
func PostStatus(ctx context.Context, client *github.Client, owner, repo, ref string, status *github.RepoStatus) error {
func PostStatus(ctx context.Context, opts *PullEvaluationOptions, client *github.Client, owner, repo, ref string, status *github.RepoStatus) error {
if opts != nil && opts.StatusCheckDryRunOnly {
zerolog.Ctx(ctx).Info().Msgf("Dry-run: would set %q status on %s to %s: %s", status.GetContext(), ref, status.GetState(), status.GetDescription())
return nil
}

zerolog.Ctx(ctx).Info().Msgf("Setting %q status on %s to %s: %s", status.GetContext(), ref, status.GetState(), status.GetDescription())
_, _, err := client.Repositories.CreateStatus(ctx, owner, repo, ref, status)
return errors.WithStack(err)
Expand Down
4 changes: 2 additions & 2 deletions server/handler/eval_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,12 @@ func (ec *EvalContext) PostStatus(ctx context.Context, state, message string) {
return
}

if err := PostStatus(ctx, ec.Client, owner, repo, sha, &status); err != nil {
if err := PostStatus(ctx, ec.Options, ec.Client, owner, repo, sha, &status); err != nil {
logger.Err(err).Msg("Failed to post repo status")
}
if ec.Options.PostInsecureStatusChecks {
status.Context = github.Ptr(ec.Options.StatusCheckContext)
if err := PostStatus(ctx, ec.Client, owner, repo, sha, &status); err != nil {
if err := PostStatus(ctx, ec.Options, ec.Client, owner, repo, sha, &status); err != nil {
logger.Err(err).Msg("Failed to post insecure repo status")
}
}
Expand Down
12 changes: 9 additions & 3 deletions server/handler/eval_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ type DescriptionPrefix struct {
type PullEvaluationOptions struct {
PolicyPath string `yaml:"policy_path"`

SharedRepository *string `yaml:"shared_repository"`
SharedPolicyBranch *string `yaml:"shared_policy_branch"`
SharedPolicyPath *string `yaml:"shared_policy_path"`
SharedOrganizationInstallationID *int64 `yaml:"shared_organization_installation_id"`
SharedOrganization *string `yaml:"shared_organization"`
SharedRepository *string `yaml:"shared_repository"`
SharedPolicyBranch *string `yaml:"shared_policy_branch"`
SharedPolicyPath *string `yaml:"shared_policy_path"`

// Ignore PolicyPath and use SharedRepository and SharedPolicyPath only.
ForceSharedPolicy bool `yaml:"force_shared_policy"`

// StatusCheckDryRunOnly will be used to determine if the status check should be dry-run only and
// not actually written to the pull request.
StatusCheckDryRunOnly bool `yaml:"status_check_dry_run_only"`

// StatusCheckContext will be used to create the status context. It will be used in the following
// pattern: <StatusCheckContext>: <Base Branch Name>
StatusCheckContext string `yaml:"status_check_context"`
Expand Down
16 changes: 14 additions & 2 deletions server/handler/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (

"github.com/google/go-github/v72/github"
"github.com/palantir/go-githubapp/appconfig"
"github.com/palantir/go-githubapp/githubapp"
"github.com/palantir/policy-bot/policy"
"github.com/palantir/policy-bot/tracing"
"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -96,12 +97,14 @@ func (cc *ConfigCache) GetOrUpdate(fn func() (*FetchedConfig, error)) (*FetchedC
type ConfigFetcher struct {
sharedConfigCache ConfigCache

Options PullEvaluationOptions
Loader *appconfig.Loader
ClientCreator githubapp.ClientCreator
Options PullEvaluationOptions
Loader *appconfig.Loader
}

func (cf *ConfigFetcher) configForSharedRepository(ctx context.Context, client *github.Client, owner string) (*FetchedConfig, error) {
var ref string
var err error
if cf.Options.SharedPolicyBranch != nil {
ref = *cf.Options.SharedPolicyBranch
} else {
Expand All @@ -113,6 +116,15 @@ func (cf *ConfigFetcher) configForSharedRepository(ctx context.Context, client *
ref = r.GetDefaultBranch()
}

// If SharedOrganization is set, both the owner organization and the client needs to be overriden
if cf.Options.SharedOrganization != nil && cf.Options.SharedOrganizationInstallationID != nil {
owner = *cf.Options.SharedOrganization
client, err = cf.ClientCreator.NewInstallationClient(*cf.Options.SharedOrganizationInstallationID)
if err != nil {
return nil, fmt.Errorf("failed to create client for shared organization %s with installation ID %d: %w", owner, *cf.Options.SharedOrganizationInstallationID, err)
}
}

file, _, _, err := client.Repositories.GetContents(ctx, owner, *cf.Options.SharedRepository, *cf.Options.SharedPolicyPath, &github.RepositoryContentGetOptions{
Ref: ref,
})
Expand Down
2 changes: 1 addition & 1 deletion server/handler/installation.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (h *Installation) postRepoInstallationStatus(ctx context.Context, client *g
State: &state,
Description: &message,
}
if err := PostStatus(ctx, client, owner, repo, head, status); err != nil {
if err := PostStatus(ctx, h.PullOpts, client, owner, repo, head, status); err != nil {
logger.Err(errors.WithStack(err)).Msg("Failed to post repo status")
}
}
4 changes: 2 additions & 2 deletions server/handler/merge_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ func (h *MergeGroup) Handle(ctx context.Context, eventType, devlieryID string, p
Description: &message,
}

if err := PostStatus(ctx, client, owner, repository, headSHA, status); err != nil {
if err := PostStatus(ctx, h.PullOpts, client, owner, repository, headSHA, status); err != nil {
logger.Err(errors.WithStack(err)).Msg("Failed to post status check for merge group")
}

if h.PullOpts.PostInsecureStatusChecks {
status.Context = github.Ptr(h.PullOpts.StatusCheckContext)
if err := PostStatus(ctx, client, owner, repository, headSHA, status); err != nil {
if err := PostStatus(ctx, h.PullOpts, client, owner, repository, headSHA, status); err != nil {
logger.Err(err).Msg("Failed to post insecure repo status")
}
}
Expand Down
11 changes: 9 additions & 2 deletions server/handler/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,15 @@ func (h *Status) processOwn(ctx context.Context, event github.StatusEvent) error
Description: &desc,
}

_, _, err = client.Repositories.CreateStatus(ctx, ownerName, repoName, commitSHA, status)
return err
if h.PullOpts.StatusCheckDryRunOnly {
return nil
}

if err := PostStatus(ctx, h.PullOpts, client, ownerName, repoName, commitSHA, status); err != nil {
logger.Err(errors.WithStack(err)).Msg("Failed to post status check for merge group")
}

return nil
}

func (h *Status) processOthers(ctx context.Context, event github.StatusEvent) error {
Expand Down
3 changes: 2 additions & 1 deletion server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ func New(ctx context.Context, c *Config) (*Server, error) {

PullOpts: &c.Options,
ConfigFetcher: &handler.ConfigFetcher{
Options: c.Options,
ClientCreator: cc,
Options: c.Options,
Loader: appconfig.NewLoader(
policyPaths,
appconfig.WithOwnerDefault(*c.Options.SharedRepository, sharedPolicyPaths),
Expand Down