From ee83bfd7afee3107be1bdf06649162a619afeac5 Mon Sep 17 00:00:00 2001 From: Alexis Couvreur Date: Tue, 5 May 2026 14:57:30 +0200 Subject: [PATCH] fix: support repository rename in resource_github_actions_repository_oidc_subject_claim_customization_template Related to https://github.com/integrations/terraform-provider-github/issues/3180 --- ...dc_subject_claim_customization_template.go | 98 ++++++++++++++----- ..._claim_customization_template_migration.go | 61 ++++++++++++ 2 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 github/resource_github_actions_repository_oidc_subject_claim_customization_template_migration.go diff --git a/github/resource_github_actions_repository_oidc_subject_claim_customization_template.go b/github/resource_github_actions_repository_oidc_subject_claim_customization_template.go index ce64a8b2d4..c4b3b695cb 100644 --- a/github/resource_github_actions_repository_oidc_subject_claim_customization_template.go +++ b/github/resource_github_actions_repository_oidc_subject_claim_customization_template.go @@ -3,21 +3,27 @@ package github import ( "context" "errors" + "net/http" "github.com/google/go-github/v85/github" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplate() *schema.Resource { return &schema.Resource{ - Create: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate, - Read: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead, - Update: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate, - Delete: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateDelete, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, + SchemaVersion: 1, + StateUpgraders: []schema.StateUpgrader{ + { + Type: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateV0().CoreConfigSchema().ImpliedType(), + Upgrade: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateStateUpgradeV0, + Version: 0, + }, }, + Schema: map[string]*schema.Schema{ "repository": { Type: schema.TypeString, @@ -25,6 +31,11 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplate() *sch Description: "The name of the repository.", ValidateDiagFunc: validation.ToDiagFunc(validation.StringLenBetween(1, 100)), }, + "repository_id": { + Type: schema.TypeInt, + Computed: true, + Description: "ID of the repository.", + }, "use_default": { Type: schema.TypeBool, Required: true, @@ -40,10 +51,22 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplate() *sch }, }, }, + + CustomizeDiff: customdiff.All( + diffRepository, + ), + + CreateContext: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate, + ReadContext: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead, + UpdateContext: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate, + DeleteContext: resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, } } -func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate(d *schema.ResourceData, meta any) error { +func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client repository := d.Get("repository").(string) @@ -53,7 +76,7 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateO includeClaimKeys, hasClaimKeys := d.GetOk("include_claim_keys") if useDefault && hasClaimKeys { - return errors.New("include_claim_keys cannot be set when use_default is true") + return diag.Errorf("include_claim_keys cannot be set when use_default is true") } customOIDCSubjectClaimTemplate := &github.OIDCSubjectClaimCustomTemplate{ @@ -61,11 +84,9 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateO } if includeClaimKeys != nil { - includeClaimKeysVal := includeClaimKeys.([]any) claimsStr := make([]string, len(includeClaimKeysVal)) - for i, v := range includeClaimKeysVal { claimsStr[i] = v.(string) } @@ -73,42 +94,65 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateCreateO customOIDCSubjectClaimTemplate.IncludeClaimKeys = claimsStr } - ctx := context.Background() _, err := client.Actions.SetRepoOIDCSubjectClaimCustomTemplate(ctx, owner, repository, customOIDCSubjectClaimTemplate) if err != nil { - return err + return diag.FromErr(err) + } + + repo, _, err := client.Repositories.Get(ctx, owner, repository) + if err != nil { + return diag.FromErr(err) } d.SetId(repository) - return resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead(d, meta) + if err := d.Set("repository_id", int(repo.GetID())); err != nil { + return diag.FromErr(err) + } + + return resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead(ctx, d, meta) } -func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead(d *schema.ResourceData, meta any) error { - client := meta.(*Owner).v3client +func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + ctx = tflog.SetField(ctx, "id", d.Id()) - repository := d.Id() + client := meta.(*Owner).v3client owner := meta.(*Owner).name - ctx := context.Background() - template, _, err := client.Actions.GetRepoOIDCSubjectClaimCustomTemplate(ctx, owner, repository) + repoName := d.Get("repository").(string) + + repo, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { - return deleteResourceOn404AndSwallow304OtherwiseReturnError(err, d, "actions repository oidc subject claim customization template (%s, %s)", owner, repository) + var ghErr *github.ErrorResponse + if errors.As(err, &ghErr) && ghErr.Response.StatusCode == http.StatusNotFound { + tflog.Info(ctx, "Repository not found, removing from state.", map[string]any{"repository": repoName}) + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + template, _, err := client.Actions.GetRepoOIDCSubjectClaimCustomTemplate(ctx, owner, repoName) + if err != nil { + return diag.FromErr(deleteResourceOn404AndSwallow304OtherwiseReturnError(err, d, "actions repository oidc subject claim customization template (%s, %s)", owner, repoName)) } - if err = d.Set("repository", repository); err != nil { - return err + if err = d.Set("repository", repo.GetName()); err != nil { + return diag.FromErr(err) + } + if err = d.Set("repository_id", int(repo.GetID())); err != nil { + return diag.FromErr(err) } if err = d.Set("use_default", template.UseDefault); err != nil { - return err + return diag.FromErr(err) } if err = d.Set("include_claim_keys", template.IncludeClaimKeys); err != nil { - return err + return diag.FromErr(err) } return nil } -func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateDelete(d *schema.ResourceData, meta any) error { +func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { // Reset the repository to use the default claims // https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#using-the-default-subject-claims client := meta.(*Owner).v3client @@ -116,14 +160,14 @@ func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateDelete( repository := d.Get("repository").(string) owner := meta.(*Owner).name + useDefault := true customOIDCSubjectClaimTemplate := &github.OIDCSubjectClaimCustomTemplate{ - UseDefault: new(true), + UseDefault: &useDefault, } - ctx := context.Background() _, err := client.Actions.SetRepoOIDCSubjectClaimCustomTemplate(ctx, owner, repository, customOIDCSubjectClaimTemplate) if err != nil { - return err + return diag.FromErr(err) } return nil diff --git a/github/resource_github_actions_repository_oidc_subject_claim_customization_template_migration.go b/github/resource_github_actions_repository_oidc_subject_claim_customization_template_migration.go new file mode 100644 index 0000000000..546b764967 --- /dev/null +++ b/github/resource_github_actions_repository_oidc_subject_claim_customization_template_migration.go @@ -0,0 +1,61 @@ +package github + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repository": { + Type: schema.TypeString, + Required: true, + Description: "The name of the repository.", + ValidateDiagFunc: validation.ToDiagFunc(validation.StringLenBetween(1, 100)), + }, + "use_default": { + Type: schema.TypeBool, + Required: true, + Description: "Whether to use the default template or not. If 'true', 'include_claim_keys' must not be set.", + }, + "include_claim_keys": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + Description: "A list of OpenID Connect claims.", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func resourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplateStateUpgradeV0(ctx context.Context, rawState map[string]any, m any) (map[string]any, error) { + meta := m.(*Owner) + client := meta.v3client + owner := meta.name + + log.Printf("[DEBUG] OIDC Subject Claim Customization Template state before migration: %#v", rawState) + + repoName, ok := rawState["repository"].(string) + if !ok { + return nil, fmt.Errorf("repository not found or is not a string") + } + + repo, _, err := client.Repositories.Get(ctx, owner, repoName) + if err != nil { + return nil, fmt.Errorf("failed to retrieve repository %s: %w", repoName, err) + } + + rawState["repository_id"] = int(repo.GetID()) + + log.Printf("[DEBUG] OIDC Subject Claim Customization Template state after migration: %#v", rawState) + + return rawState, nil +}