terraform-provider-github icon indicating copy to clipboard operation
terraform-provider-github copied to clipboard

Setting members_can_fork_private_repositories resets organisational fork policy

Open fatbasstard opened this issue 2 years ago • 5 comments

We're now using the github_organization_settings to configure some organisational settings (instead of "manual") and we noticed that settings members_can_fork_private_repositories works in unexpected ways with the organisational settings:

image

We had forking set to User accounts, imported the github_organization_settings resource (where members_can_fork_private_repositories apparantly is set to True and not TF changes this to the "Default" Organisations within this enterprise.

This is quite unexpected behaviour, and after reading up other issues decided to remove this setting from the resource entirely. When removing it TF actually said it would change the setting (update members_can_fork_private_repositories : true change to false). But the setting is now kept intact.

So:

  • Organisation settings and Forking looks "off" (could be related to Enterprise)
  • Is there a resource to change the forking policy of an (enterprise) organisation?

Related links:

  • https://github.com/integrations/terraform-provider-github/issues/1199
  • https://github.com/integrations/terraform-provider-github/issues/1333
  • https://github.com/integrations/terraform-provider-github/pull/1362

fatbasstard avatar Aug 17 '23 10:08 fatbasstard

I'm sorry, I'm not quite sure what you mean by:

This is quite unexpected behaviour, and after reading up other issues decided to remove this setting from the resource entirely. When removing it TF actually said it would change the setting (update members_can_fork_private_repositories : true change to false). But the setting is now kept intact.

Would you mind rephrasing this for me a little differently and I can try to help troubleshoot?

kfcampbell avatar Aug 18 '23 18:08 kfcampbell

Hi @kfcampbell,

Organisation setting in the GUI:

image

Applying Terraform with the following (which gives no changes):

resource "github_organization_settings" "connectedbrewery" {
...
  members_can_fork_private_repositories = true
...
}

image

fatbasstard avatar Aug 24 '23 09:08 fatbasstard

👋 Hey Friends, this issue has been automatically marked as stale because it has no recent activity. It will be closed if no further activity occurs. Please add the Status: Pinned label if you feel that this issue needs to remain open/active. Thank you for your contributions and help in keeping things tidy!

github-actions[bot] avatar May 21 '24 01:05 github-actions[bot]

Any update on this issue?

fatbasstard avatar May 22 '24 08:05 fatbasstard

We use github_organization_settings with members_can_fork_private_repositories ~but are not seeing the sub-setting for the fork destination being reset by Terraform~ I spoke too soon - if the TF apply touches github_organization_settings, even though the change is not shown in the plan, it will reset the settings.

It would be good to be able to set this in TF instead of manually though.

tpham-drw avatar Jul 19 '24 11:07 tpham-drw

+1 on this. Its less about being a bug and more about needing to add the feature of being able to select which rule to apply for forking private repos.

minsis avatar Oct 23 '24 19:10 minsis

Also wanted to mention I took a quick look at the GitHub API and I don't see any field that actually sets the forking rule when enabling members_can_fork_private_repositories. So, this could end up being a limitation on the GitHub API. https://docs.github.com/en/rest/orgs/orgs?apiVersion=2022-11-28#update-an-organization

I also tested some other scenarios directly on the API and here is what I've found so far:

  • Submitting only members_can_fork_private_repositories=false results expected behavior of disabling said property
  • Submitting only members_can_fork_private_repositories=true when previous setting was false will enable said property with the first option selected.
  • Submitting only members_can_fork_private_repositories=true when already set to true will reset the property back to the first option, regardless of what it was previously.
  • Submitting any other property by itself (I used default_repository_permission=write) while members_can_fork_private_repositories=true AND selected any other option will not change the options selected for members_can_fork_private_repositories
  • Submitting any other property (I used default_repository_permission=write) AND members_can_fork_private_repositories=true will reset the property back to the first option, regardless of what it was previously.

So, without really digging into the code (because I suck at go), my assumption is that the provider is redundantly submitting members_can_fork_private_repositories: true regardless of changes to said property defined in the template.

I guess maybe the work around might be to exclude submitting this property if its already set to true, and only submit if it is changing from false to true.

Also, maybe creating a feature request or something to GitHub to update the management of this property, not sure how that is actually done. I am an enterprise customer so if I can help make this request, I'd be happy to.

minsis avatar Oct 23 '24 20:10 minsis

Have any of the contributors been able to investigate this issue?

minsis avatar Feb 03 '25 17:02 minsis

I've tried a lot of different approaches and here is a workaround which works for me for now.

It has to be run before and after terraform:

./enterprise-policies.sh unset
terraform apply  # or tofu apply
./enterprise-policies.sh
#!/usr/bin/env bash

# enterprise-policies.sh

set -euo pipefail

# Configure enterprise settings which can't be done through GitHub Terraform Provider at the moment of writing this script

ENTERPRISE_SLUG="my-org"

usage() {
  echo "Usage: $(basename "$0") [-h|--help|unset]"
  echo
  echo "Options:"
  echo "  -h, --help  Display this help message"
  echo "  unset     Disable enterprise policies"
}

graphql_request() {
  local data=$1

  local response; response=$(
    curl -fsS -X POST \
      -H "Authorization: bearer $GITHUB_TOKEN" \
      -H "Content-Type: application/json" \
      -d "$data" \
      https://api.github.com/graphql
  )

  local errors; errors=$(jq -r '(.errors // empty)[] | "ERROR: " + .message' <<< "$response")

  if [[ -n "$errors" ]]; then
    echo "$errors" >&2
    return 1
  fi

  echo "$response"
}

get_enterprise_id() {
  local slug=$1

  local query='
    query($slug: String!) {
      enterprise(slug: $slug) {
        id
      }
    }
  '

  local variables; variables=$(
    jq -n \
      --arg slug "$slug" \
      '{
          "slug": $slug
       }'
  )

  local data; data=$(jq -n --arg query "$query" --arg variables "$variables" '{ query: $query, variables: $variables }')

  graphql_request "$data" | jq -r .data.enterprise.id
}

enterprise_set_repo_forking_settings() {
  local enterprise_id=$1
  local action=${2:-ENABLED}

  local query='
    mutation($enterpriseId: ID!, $action: EnterpriseEnabledDisabledSettingValue!) {
      updateEnterpriseAllowPrivateRepositoryForkingSetting(
        input: {
          enterpriseId: $enterpriseId,
          settingValue: $action,
          policyValue: USER_ACCOUNTS  # Allow private repository forking only for user accounts
        }
      ) {
        message
      }
    }
  '

  local variables; variables=$(
    jq -n \
      --arg enterprise_id "$enterprise_id" \
      --arg action "$action" \
      '{
          "enterpriseId": $enterprise_id,
          "action": $action
       }'
  )

  local data; data=$(jq -n --arg query "$query" --arg variables "$variables" '{ query: $query, variables: $variables }')

  graphql_request "$data" | jq -r '"INFO: " + .data.updateEnterpriseAllowPrivateRepositoryForkingSetting.message'
}

main() {
  [[ "$@" == "-h" || "$@" == "--help" ]] && { usage; exit 0; }

  local enterprise_slug="$ENTERPRISE_SLUG"
  local enterprise_id; enterprise_id=$(get_enterprise_id "$enterprise_slug")

  if [[ "$#" -eq 0 ]]; then
    enterprise_set_repo_forking_settings "$enterprise_id"
  elif [[ "$@" == "unset" ]]; then
    enterprise_set_repo_forking_settings "$enterprise_id" NO_POLICY
  else
    usage
    exit 1
  fi
}

main "$@"

giner avatar Feb 10 '25 09:02 giner