Skip to content

Commit 67e8de1

Browse files
committed
feat: Add custom property to oidc token
1 parent 94f71cf commit 67e8de1

6 files changed

Lines changed: 446 additions & 0 deletions
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package github
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
)
9+
10+
func dataSourceGithubActionsOrganizationOIDCCustomPropertyInclusions() *schema.Resource {
11+
return &schema.Resource{
12+
ReadContext: dataSourceGithubActionsOrganizationOIDCCustomPropertyInclusionsRead,
13+
14+
Schema: map[string]*schema.Schema{
15+
"custom_property_names": {
16+
Type: schema.TypeList,
17+
Computed: true,
18+
Description: "A list of custom property names included in the OIDC token.",
19+
Elem: &schema.Schema{
20+
Type: schema.TypeString,
21+
},
22+
},
23+
},
24+
}
25+
}
26+
27+
func dataSourceGithubActionsOrganizationOIDCCustomPropertyInclusionsRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
28+
client := meta.(*Owner).v3client
29+
orgName := meta.(*Owner).name
30+
31+
err := checkOrganization(meta)
32+
if err != nil {
33+
return diag.FromErr(err)
34+
}
35+
36+
inclusions, err := listOrgOIDCCustomPropertyInclusions(ctx, client, orgName)
37+
if err != nil {
38+
return diag.FromErr(err)
39+
}
40+
41+
propertyNames := make([]string, len(inclusions))
42+
for i, inclusion := range inclusions {
43+
propertyNames[i] = inclusion.PropertyName
44+
}
45+
46+
d.SetId(orgName)
47+
if err := d.Set("custom_property_names", propertyNames); err != nil {
48+
return diag.FromErr(err)
49+
}
50+
51+
return nil
52+
}

github/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ func Provider() *schema.Provider {
137137
"github_actions_environment_secret": resourceGithubActionsEnvironmentSecret(),
138138
"github_actions_environment_variable": resourceGithubActionsEnvironmentVariable(),
139139
"github_actions_organization_oidc_subject_claim_customization_template": resourceGithubActionsOrganizationOIDCSubjectClaimCustomizationTemplate(),
140+
"github_actions_organization_oidc_custom_property_inclusion": resourceGithubActionsOrganizationOIDCCustomPropertyInclusion(),
140141
"github_actions_organization_permissions": resourceGithubActionsOrganizationPermissions(),
141142
"github_actions_organization_secret": resourceGithubActionsOrganizationSecret(),
142143
"github_actions_organization_secret_repositories": resourceGithubActionsOrganizationSecretRepositories(),
@@ -225,6 +226,7 @@ func Provider() *schema.Provider {
225226
"github_actions_environment_secrets": dataSourceGithubActionsEnvironmentSecrets(),
226227
"github_actions_environment_variables": dataSourceGithubActionsEnvironmentVariables(),
227228
"github_actions_organization_oidc_subject_claim_customization_template": dataSourceGithubActionsOrganizationOIDCSubjectClaimCustomizationTemplate(),
229+
"github_actions_organization_oidc_custom_property_inclusions": dataSourceGithubActionsOrganizationOIDCCustomPropertyInclusions(),
228230
"github_actions_organization_public_key": dataSourceGithubActionsOrganizationPublicKey(),
229231
"github_actions_organization_registration_token": dataSourceGithubActionsOrganizationRegistrationToken(),
230232
"github_actions_organization_secrets": dataSourceGithubActionsOrganizationSecrets(),
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/google/go-github/v84/github"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
)
10+
11+
func resourceGithubActionsOrganizationOIDCCustomPropertyInclusion() *schema.Resource {
12+
return &schema.Resource{
13+
Create: resourceGithubActionsOrganizationOIDCCustomPropertyInclusionCreate,
14+
Read: resourceGithubActionsOrganizationOIDCCustomPropertyInclusionRead,
15+
Delete: resourceGithubActionsOrganizationOIDCCustomPropertyInclusionDelete,
16+
Importer: &schema.ResourceImporter{
17+
StateContext: schema.ImportStatePassthroughContext,
18+
},
19+
Schema: map[string]*schema.Schema{
20+
"custom_property_name": {
21+
Type: schema.TypeString,
22+
Required: true,
23+
ForceNew: true,
24+
Description: "The name of the custom property to include in the OIDC token.",
25+
},
26+
},
27+
}
28+
}
29+
30+
func resourceGithubActionsOrganizationOIDCCustomPropertyInclusionCreate(d *schema.ResourceData, meta any) error {
31+
client := meta.(*Owner).v3client
32+
orgName := meta.(*Owner).name
33+
ctx := context.Background()
34+
35+
err := checkOrganization(meta)
36+
if err != nil {
37+
return err
38+
}
39+
40+
customPropertyName := d.Get("custom_property_name").(string)
41+
42+
body := map[string]string{
43+
"custom_property_name": customPropertyName,
44+
}
45+
46+
req, err := client.NewRequest("POST", fmt.Sprintf("orgs/%s/actions/oidc/customization/properties/repo", orgName), body)
47+
if err != nil {
48+
return fmt.Errorf("error creating request to add OIDC custom property inclusion: %w", err)
49+
}
50+
51+
_, err = client.Do(ctx, req, nil)
52+
if err != nil {
53+
return fmt.Errorf("error adding OIDC custom property inclusion %q for organization %q: %w", customPropertyName, orgName, err)
54+
}
55+
56+
d.SetId(buildTwoPartID(orgName, customPropertyName))
57+
58+
return resourceGithubActionsOrganizationOIDCCustomPropertyInclusionRead(d, meta)
59+
}
60+
61+
func resourceGithubActionsOrganizationOIDCCustomPropertyInclusionRead(d *schema.ResourceData, meta any) error {
62+
client := meta.(*Owner).v3client
63+
ctx := context.Background()
64+
65+
orgName, customPropertyName, err := parseTwoPartID(d.Id(), "organization", "custom_property_name")
66+
if err != nil {
67+
return err
68+
}
69+
70+
err = checkOrganization(meta)
71+
if err != nil {
72+
return err
73+
}
74+
75+
inclusions, err := listOrgOIDCCustomPropertyInclusions(ctx, client, orgName)
76+
if err != nil {
77+
return fmt.Errorf("error reading OIDC custom property inclusions for organization %q: %w", orgName, err)
78+
}
79+
80+
found := false
81+
for _, inclusion := range inclusions {
82+
if inclusion.PropertyName == customPropertyName {
83+
found = true
84+
break
85+
}
86+
}
87+
88+
if !found {
89+
d.SetId("")
90+
return nil
91+
}
92+
93+
if err := d.Set("custom_property_name", customPropertyName); err != nil {
94+
return err
95+
}
96+
97+
return nil
98+
}
99+
100+
func resourceGithubActionsOrganizationOIDCCustomPropertyInclusionDelete(d *schema.ResourceData, meta any) error {
101+
client := meta.(*Owner).v3client
102+
ctx := context.Background()
103+
104+
orgName, customPropertyName, err := parseTwoPartID(d.Id(), "organization", "custom_property_name")
105+
if err != nil {
106+
return err
107+
}
108+
109+
err = checkOrganization(meta)
110+
if err != nil {
111+
return err
112+
}
113+
114+
req, err := client.NewRequest("DELETE", fmt.Sprintf("orgs/%s/actions/oidc/customization/properties/repo/%s", orgName, customPropertyName), nil)
115+
if err != nil {
116+
return fmt.Errorf("error creating request to delete OIDC custom property inclusion: %w", err)
117+
}
118+
119+
_, err = client.Do(ctx, req, nil)
120+
if err != nil {
121+
return fmt.Errorf("error deleting OIDC custom property inclusion %q for organization %q: %w", customPropertyName, orgName, err)
122+
}
123+
124+
return nil
125+
}
126+
127+
// OIDCCustomPropertyInclusion represents a custom property included in OIDC tokens.
128+
type OIDCCustomPropertyInclusion struct {
129+
PropertyName string `json:"property_name"`
130+
}
131+
132+
// listOrgOIDCCustomPropertyInclusions lists all custom properties included in OIDC tokens for an organization.
133+
func listOrgOIDCCustomPropertyInclusions(ctx context.Context, client *github.Client, orgName string) ([]*OIDCCustomPropertyInclusion, error) {
134+
req, err := client.NewRequest("GET", fmt.Sprintf("orgs/%s/actions/oidc/customization/properties/repo", orgName), nil)
135+
if err != nil {
136+
return nil, err
137+
}
138+
139+
var inclusions []*OIDCCustomPropertyInclusion
140+
_, err = client.Do(ctx, req, &inclusions)
141+
if err != nil {
142+
return nil, err
143+
}
144+
145+
return inclusions, nil
146+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package github
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
)
8+
9+
func TestAccGithubActionsOrganizationOIDCCustomPropertyInclusion(t *testing.T) {
10+
t.Run("creates and deletes an OIDC custom property inclusion without error", func(t *testing.T) {
11+
config := `
12+
resource "github_actions_organization_oidc_custom_property_inclusion" "test" {
13+
custom_property_name = "environment"
14+
}`
15+
16+
check := resource.ComposeTestCheckFunc(
17+
resource.TestCheckResourceAttr(
18+
"github_actions_organization_oidc_custom_property_inclusion.test",
19+
"custom_property_name", "environment",
20+
),
21+
)
22+
resource.Test(t, resource.TestCase{
23+
PreCheck: func() { skipUnlessHasOrgs(t) },
24+
ProviderFactories: providerFactories,
25+
Steps: []resource.TestStep{
26+
{
27+
Config: config,
28+
Check: check,
29+
},
30+
},
31+
})
32+
})
33+
34+
t.Run("imports an OIDC custom property inclusion without error", func(t *testing.T) {
35+
config := `
36+
resource "github_actions_organization_oidc_custom_property_inclusion" "test" {
37+
custom_property_name = "environment"
38+
}`
39+
40+
check := resource.ComposeTestCheckFunc(
41+
resource.TestCheckResourceAttr(
42+
"github_actions_organization_oidc_custom_property_inclusion.test",
43+
"custom_property_name", "environment",
44+
),
45+
)
46+
47+
resource.Test(t, resource.TestCase{
48+
PreCheck: func() { skipUnlessHasOrgs(t) },
49+
ProviderFactories: providerFactories,
50+
Steps: []resource.TestStep{
51+
{
52+
Config: config,
53+
Check: check,
54+
},
55+
{
56+
ResourceName: "github_actions_organization_oidc_custom_property_inclusion.test",
57+
ImportState: true,
58+
ImportStateVerify: true,
59+
},
60+
},
61+
})
62+
})
63+
64+
t.Run("manages multiple OIDC custom property inclusions", func(t *testing.T) {
65+
config := `
66+
resource "github_actions_organization_oidc_custom_property_inclusion" "env" {
67+
custom_property_name = "environment"
68+
}
69+
70+
resource "github_actions_organization_oidc_custom_property_inclusion" "team" {
71+
custom_property_name = "team"
72+
}`
73+
74+
check := resource.ComposeTestCheckFunc(
75+
resource.TestCheckResourceAttr(
76+
"github_actions_organization_oidc_custom_property_inclusion.env",
77+
"custom_property_name", "environment",
78+
),
79+
resource.TestCheckResourceAttr(
80+
"github_actions_organization_oidc_custom_property_inclusion.team",
81+
"custom_property_name", "team",
82+
),
83+
)
84+
85+
resource.Test(t, resource.TestCase{
86+
PreCheck: func() { skipUnlessHasOrgs(t) },
87+
ProviderFactories: providerFactories,
88+
Steps: []resource.TestStep{
89+
{
90+
Config: config,
91+
Check: check,
92+
},
93+
},
94+
})
95+
})
96+
}
97+
98+
func TestAccGithubActionsOrganizationOIDCCustomPropertyInclusionsDataSource(t *testing.T) {
99+
t.Run("reads OIDC custom property inclusions without error", func(t *testing.T) {
100+
config := `
101+
resource "github_actions_organization_oidc_custom_property_inclusion" "test" {
102+
custom_property_name = "environment"
103+
}
104+
105+
data "github_actions_organization_oidc_custom_property_inclusions" "test" {
106+
depends_on = [github_actions_organization_oidc_custom_property_inclusion.test]
107+
}`
108+
109+
check := resource.ComposeTestCheckFunc(
110+
resource.TestCheckResourceAttrSet(
111+
"data.github_actions_organization_oidc_custom_property_inclusions.test",
112+
"custom_property_names.#",
113+
),
114+
)
115+
resource.Test(t, resource.TestCase{
116+
PreCheck: func() { skipUnlessHasOrgs(t) },
117+
ProviderFactories: providerFactories,
118+
Steps: []resource.TestStep{
119+
{
120+
Config: config,
121+
Check: check,
122+
},
123+
},
124+
})
125+
})
126+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
layout: "github"
3+
page_title: "GitHub: github_actions_organization_oidc_custom_property_inclusions"
4+
description: |-
5+
Lists the repository custom properties included in OIDC tokens for a GitHub organization
6+
---
7+
8+
# github_actions_organization_oidc_custom_property_inclusions
9+
10+
Use this data source to retrieve the list of repository custom properties that are included in the OIDC token for
11+
repository actions in a GitHub organization.
12+
13+
## Example Usage
14+
15+
```hcl
16+
data "github_actions_organization_oidc_custom_property_inclusions" "example" {}
17+
18+
output "included_properties" {
19+
value = data.github_actions_organization_oidc_custom_property_inclusions.example.custom_property_names
20+
}
21+
```
22+
23+
## Argument Reference
24+
25+
This data source has no required arguments.
26+
27+
## Attributes Reference
28+
29+
* `custom_property_names` - A list of custom property names that are included in the OIDC token.

0 commit comments

Comments
 (0)