Skip to content

Commit 6df631f

Browse files
andrewesweetclaude
andcommitted
feat: add github_enterprise_private_repository_forking_setting resource
Add a new resource to manage the enterprise-level policy that controls whether and where members can fork private and internal repositories. This uses the GraphQL mutation updateEnterpriseAllowPrivateRepositoryForkingSetting to set: - setting_value: ENABLED, DISABLED, or NO_POLICY - policy_value: controls fork destinations (e.g. SAME_ORGANIZATION, ENTERPRISE_ORGANIZATIONS_USER_ACCOUNTS, EVERYWHERE, etc.) The resource includes CustomizeDiff validation ensuring policy_value is required when enabled and forbidden otherwise. Delete resets to NO_POLICY, returning control to individual organizations. Relates to #2851, #1844 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 7905a12 commit 6df631f

4 files changed

Lines changed: 529 additions & 0 deletions

github/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ func Provider() *schema.Provider {
218218
"github_enterprise_ip_allow_list_entry": resourceGithubEnterpriseIpAllowListEntry(),
219219
"github_enterprise_actions_workflow_permissions": resourceGithubEnterpriseActionsWorkflowPermissions(),
220220
"github_actions_organization_workflow_permissions": resourceGithubActionsOrganizationWorkflowPermissions(),
221+
"github_enterprise_private_repository_forking_setting": resourceGithubEnterprisePrivateRepositoryForkingSetting(),
221222
"github_enterprise_security_analysis_settings": resourceGithubEnterpriseSecurityAnalysisSettings(),
222223
"github_workflow_repository_permissions": resourceGithubWorkflowRepositoryPermissions(),
223224
},
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
10+
"github.com/shurcooL/githubv4"
11+
)
12+
13+
func resourceGithubEnterprisePrivateRepositoryForkingSetting() *schema.Resource {
14+
return &schema.Resource{
15+
Description: "Manages the private repository forking policy for a GitHub Enterprise.",
16+
Create: resourceGithubEnterprisePrivateRepositoryForkingSettingCreateOrUpdate,
17+
Read: resourceGithubEnterprisePrivateRepositoryForkingSettingRead,
18+
Update: resourceGithubEnterprisePrivateRepositoryForkingSettingCreateOrUpdate,
19+
Delete: resourceGithubEnterprisePrivateRepositoryForkingSettingDelete,
20+
Importer: &schema.ResourceImporter{
21+
StateContext: schema.ImportStatePassthroughContext,
22+
},
23+
24+
CustomizeDiff: func(_ context.Context, diff *schema.ResourceDiff, _ any) error {
25+
settingValue := diff.Get("setting_value").(string)
26+
policyValue := diff.Get("policy_value").(string)
27+
28+
if settingValue == "ENABLED" && policyValue == "" {
29+
return fmt.Errorf("policy_value is required when setting_value is ENABLED")
30+
}
31+
if settingValue != "ENABLED" && policyValue != "" {
32+
return fmt.Errorf("policy_value must not be set when setting_value is %s", settingValue)
33+
}
34+
return nil
35+
},
36+
37+
Schema: map[string]*schema.Schema{
38+
"enterprise_slug": {
39+
Type: schema.TypeString,
40+
Required: true,
41+
ForceNew: true,
42+
Description: "The slug of the enterprise.",
43+
},
44+
"setting_value": {
45+
Type: schema.TypeString,
46+
Required: true,
47+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
48+
"ENABLED",
49+
"DISABLED",
50+
"NO_POLICY",
51+
}, false)),
52+
Description: "Whether private repository forking is enabled for the enterprise. Must be one of: ENABLED, DISABLED, NO_POLICY.",
53+
},
54+
"policy_value": {
55+
Type: schema.TypeString,
56+
Optional: true,
57+
ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
58+
"ENTERPRISE_ORGANIZATIONS",
59+
"SAME_ORGANIZATION",
60+
"SAME_ORGANIZATION_USER_ACCOUNTS",
61+
"ENTERPRISE_ORGANIZATIONS_USER_ACCOUNTS",
62+
"USER_ACCOUNTS",
63+
"EVERYWHERE",
64+
}, false)),
65+
Description: "Where members can fork private repositories. Required when setting_value is ENABLED. Must be one of: ENTERPRISE_ORGANIZATIONS, SAME_ORGANIZATION, SAME_ORGANIZATION_USER_ACCOUNTS, ENTERPRISE_ORGANIZATIONS_USER_ACCOUNTS, USER_ACCOUNTS, EVERYWHERE.",
66+
},
67+
},
68+
}
69+
}
70+
71+
func resourceGithubEnterprisePrivateRepositoryForkingSettingCreateOrUpdate(d *schema.ResourceData, meta any) error {
72+
client := meta.(*Owner).v4client
73+
ctx := context.Background()
74+
75+
enterpriseSlug := d.Get("enterprise_slug").(string)
76+
77+
enterpriseID, err := getEnterpriseID(ctx, client, enterpriseSlug)
78+
if err != nil {
79+
return fmt.Errorf("error resolving enterprise ID for slug %q: %w", enterpriseSlug, err)
80+
}
81+
82+
settingValue := githubv4.EnterpriseEnabledDisabledSettingValue(d.Get("setting_value").(string))
83+
84+
input := githubv4.UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput{
85+
EnterpriseID: enterpriseID,
86+
SettingValue: settingValue,
87+
}
88+
89+
if v, ok := d.GetOk("policy_value"); ok {
90+
pv := githubv4.EnterpriseAllowPrivateRepositoryForkingPolicyValue(v.(string))
91+
input.PolicyValue = &pv
92+
}
93+
94+
var mutate struct {
95+
UpdateEnterpriseAllowPrivateRepositoryForkingSetting struct {
96+
Enterprise struct {
97+
ID githubv4.ID
98+
}
99+
Message githubv4.String
100+
} `graphql:"updateEnterpriseAllowPrivateRepositoryForkingSetting(input: $input)"`
101+
}
102+
103+
log.Printf("[DEBUG] Updating private repository forking setting for enterprise: %s", enterpriseSlug)
104+
err = client.Mutate(ctx, &mutate, input, nil)
105+
if err != nil {
106+
return fmt.Errorf("error updating private repository forking setting for enterprise %q: %w", enterpriseSlug, err)
107+
}
108+
109+
d.SetId(enterpriseSlug)
110+
111+
return resourceGithubEnterprisePrivateRepositoryForkingSettingRead(d, meta)
112+
}
113+
114+
func resourceGithubEnterprisePrivateRepositoryForkingSettingRead(d *schema.ResourceData, meta any) error {
115+
client := meta.(*Owner).v4client
116+
ctx := context.Background()
117+
118+
enterpriseSlug := d.Id()
119+
120+
var query struct {
121+
Enterprise struct {
122+
OwnerInfo struct {
123+
AllowPrivateRepositoryForkingSetting githubv4.EnterpriseEnabledDisabledSettingValue
124+
AllowPrivateRepositoryForkingSettingPolicyValue githubv4.EnterpriseAllowPrivateRepositoryForkingPolicyValue
125+
}
126+
} `graphql:"enterprise(slug: $slug)"`
127+
}
128+
129+
variables := map[string]any{
130+
"slug": githubv4.String(enterpriseSlug),
131+
}
132+
133+
log.Printf("[DEBUG] Reading private repository forking setting for enterprise: %s", enterpriseSlug)
134+
err := client.Query(ctx, &query, variables)
135+
if err != nil {
136+
return fmt.Errorf("error reading private repository forking setting for enterprise %q: %w", enterpriseSlug, err)
137+
}
138+
139+
if err := d.Set("enterprise_slug", enterpriseSlug); err != nil {
140+
return err
141+
}
142+
143+
settingValue := string(query.Enterprise.OwnerInfo.AllowPrivateRepositoryForkingSetting)
144+
if err := d.Set("setting_value", settingValue); err != nil {
145+
return err
146+
}
147+
148+
if settingValue == "ENABLED" {
149+
if err := d.Set("policy_value", string(query.Enterprise.OwnerInfo.AllowPrivateRepositoryForkingSettingPolicyValue)); err != nil {
150+
return err
151+
}
152+
} else {
153+
if err := d.Set("policy_value", ""); err != nil {
154+
return err
155+
}
156+
}
157+
158+
return nil
159+
}
160+
161+
func resourceGithubEnterprisePrivateRepositoryForkingSettingDelete(d *schema.ResourceData, meta any) error {
162+
client := meta.(*Owner).v4client
163+
ctx := context.Background()
164+
165+
enterpriseSlug := d.Id()
166+
167+
enterpriseID, err := getEnterpriseID(ctx, client, enterpriseSlug)
168+
if err != nil {
169+
return fmt.Errorf("error resolving enterprise ID for slug %q: %w", enterpriseSlug, err)
170+
}
171+
172+
input := githubv4.UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput{
173+
EnterpriseID: enterpriseID,
174+
SettingValue: githubv4.EnterpriseEnabledDisabledSettingValueNoPolicy,
175+
}
176+
177+
var mutate struct {
178+
UpdateEnterpriseAllowPrivateRepositoryForkingSetting struct {
179+
Enterprise struct {
180+
ID githubv4.ID
181+
}
182+
} `graphql:"updateEnterpriseAllowPrivateRepositoryForkingSetting(input: $input)"`
183+
}
184+
185+
log.Printf("[DEBUG] Resetting private repository forking setting to NO_POLICY for enterprise: %s", enterpriseSlug)
186+
err = client.Mutate(ctx, &mutate, input, nil)
187+
if err != nil {
188+
return fmt.Errorf("error resetting private repository forking setting for enterprise %q: %w", enterpriseSlug, err)
189+
}
190+
191+
return nil
192+
}

0 commit comments

Comments
 (0)