From 0e5b4c3c1d8f8503793dc3f6ad4c0b92345965fe Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sun, 8 Feb 2026 13:28:44 +0200 Subject: [PATCH 01/15] Add resource for repository vulnerability alerts Signed-off-by: Timo Sand --- .../github_repository_vulnerability_alerts.go | 146 +++++++++++++ ...ub_repository_vulnerability_alerts_test.go | 193 ++++++++++++++++++ github/provider.go | 1 + ...ository_vulnerability_alerts.html.markdown | 46 +++++ 4 files changed, 386 insertions(+) create mode 100644 github/github_repository_vulnerability_alerts.go create mode 100644 github/github_repository_vulnerability_alerts_test.go create mode 100644 website/docs/r/repository_vulnerability_alerts.html.markdown diff --git a/github/github_repository_vulnerability_alerts.go b/github/github_repository_vulnerability_alerts.go new file mode 100644 index 0000000000..d9e4559cd0 --- /dev/null +++ b/github/github_repository_vulnerability_alerts.go @@ -0,0 +1,146 @@ +package github + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceGithubRepositoryVulnerabilityAlerts() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceGithubRepositoryVulnerabilityAlertsCreate, + ReadContext: resourceGithubRepositoryVulnerabilityAlertsRead, + UpdateContext: resourceGithubRepositoryVulnerabilityAlertsUpdate, + DeleteContext: resourceGithubRepositoryVulnerabilityAlertsDelete, + Importer: &schema.ResourceImporter{ + StateContext: resourceGithubRepositoryVulnerabilityAlertsImport, + }, + + Schema: map[string]*schema.Schema{ + "repository_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The repository name to configure vulnerability alerts for.", + }, + "repository_owner": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The owner of the repository to configure vulnerability alerts for.", + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Whether vulnerability alerts are enabled for the repository.", + }, + }, + } +} + +func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + + owner := d.Get("repository_owner").(string) + repoName := d.Get("repository_name").(string) + + vulnerabilityAlertsEnabled := d.Get("enabled").(bool) + if vulnerabilityAlertsEnabled { + _, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + } else { + _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + } + + id, err := buildID(owner, repoName) + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + + return nil +} + +func resourceGithubRepositoryVulnerabilityAlertsRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + + owner := d.Get("repository_owner").(string) + repoName := d.Get("repository_name").(string) + vulnerabilityAlertsEnabled, _, err := client.Repositories.GetVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.Errorf("error reading repository vulnerability alerts: %s", err.Error()) + } + if err = d.Set("enabled", vulnerabilityAlertsEnabled); err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceGithubRepositoryVulnerabilityAlertsUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + + owner := d.Get("repository_owner").(string) + repoName := d.Get("repository_name").(string) + + vulnerabilityAlertsEnabled := d.Get("enabled").(bool) + if vulnerabilityAlertsEnabled { + _, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + } else { + _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + } + + return nil +} + +func resourceGithubRepositoryVulnerabilityAlertsDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + + owner := d.Get("repository_owner").(string) + repoName := d.Get("repository_name").(string) + _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) + if err != nil { + return diag.FromErr(handleArchivedRepoDelete(err, "repository vulnerability alerts", d.Id(), owner, repoName)) + } + + return nil +} + +func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { + repoOwner, repoName, err := parseID2(d.Id()) + if err != nil { + return nil, fmt.Errorf("invalid ID specified: supplied ID must be written as /. Original error: %w", err) + } + if err := d.Set("repository_owner", repoOwner); err != nil { + return nil, err + } + if err := d.Set("repository_name", repoName); err != nil { + return nil, err + } + + id, err := buildID(repoOwner, repoName) + if err != nil { + return nil, err + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} diff --git a/github/github_repository_vulnerability_alerts_test.go b/github/github_repository_vulnerability_alerts_test.go new file mode 100644 index 0000000000..f4710b6b5c --- /dev/null +++ b/github/github_repository_vulnerability_alerts_test.go @@ -0,0 +1,193 @@ +package github + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { + t.Run("enables_vulnerability_alerts_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository_name = github_repository.test.name + repository_owner = "%s" + enabled = true + } + `, repoName, testAccConf.owner) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "repository_name", repoName), + ), + }, + }, + }) + }) + + t.Run("disables_vulnerability_alerts_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository_name = github_repository.test.name + repository_owner = "%s" + enabled = false + } + `, repoName, testAccConf.owner) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), + ), + }, + }, + }) + }) + + t.Run("updates_vulnerability_alerts_from_disabled_to_enabled", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + enabled := false + updatedEnabled := true + + config := ` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository_name = github_repository.test.name + repository_owner = "%s" + enabled = %t + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(config, repoName, testAccConf.owner, enabled), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), + ), + }, + { + Config: fmt.Sprintf(config, repoName, testAccConf.owner, updatedEnabled), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), + ), + }, + }, + }) + }) + + t.Run("updates_vulnerability_alerts_from_enabled_to_disabled", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + enabled := true + updatedEnabled := false + + config := ` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository_name = github_repository.test.name + repository_owner = "%s" + enabled = %t + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(config, repoName, testAccConf.owner, enabled), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), + ), + }, + { + Config: fmt.Sprintf(config, repoName, testAccConf.owner, updatedEnabled), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), + ), + }, + }, + }) + }) + + t.Run("imports_vulnerability_alerts_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository_name = github_repository.test.name + repository_owner = "%s" + enabled = true + } + `, repoName, testAccConf.owner) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), + ), + }, + { + ResourceName: "github_repository_vulnerability_alerts.test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) + }) +} diff --git a/github/provider.go b/github/provider.go index 2d5d6dc33a..b5375cf240 100644 --- a/github/provider.go +++ b/github/provider.go @@ -203,6 +203,7 @@ func Provider() *schema.Provider { "github_repository_ruleset": resourceGithubRepositoryRuleset(), "github_repository_topics": resourceGithubRepositoryTopics(), "github_repository_webhook": resourceGithubRepositoryWebhook(), + "github_repository_vulnerability_alerts": resourceGithubRepositoryVulnerabilityAlerts(), "github_team": resourceGithubTeam(), "github_team_members": resourceGithubTeamMembers(), "github_team_membership": resourceGithubTeamMembership(), diff --git a/website/docs/r/repository_vulnerability_alerts.html.markdown b/website/docs/r/repository_vulnerability_alerts.html.markdown new file mode 100644 index 0000000000..d09b23495b --- /dev/null +++ b/website/docs/r/repository_vulnerability_alerts.html.markdown @@ -0,0 +1,46 @@ +--- +layout: "github" +page_title: "GitHub: github_repository_vulnerability_alerts" +description: |- + Manages vulnerability alerts for a GitHub repository +--- + +# github_repository_vulnerability_alerts + +This resource allows you to manage vulnerability alerts for a GitHub repository. See the +[documentation](https://docs.github.com/en/code-security/dependabot/dependabot-alerts/about-dependabot-alerts) +for details of usage and how this will impact your repository. + +## Example Usage + +```hcl +resource "github_repository" "example" { + name = "my-repo" + description = "GitHub repo managed by Terraform" + visibility = "private" +} + +resource "github_repository_vulnerability_alerts" "example" { + repository_owner = "my-org" + repository_name = github_repository.example.name + enabled = true +} +``` + +## Argument Reference + +The following arguments are supported: + +- `repository_owner` - (Required) The owner of the repository to configure vulnerability alerts for. + +- `repository_name` - (Required) The name of the repository to configure vulnerability alerts for. + +- `enabled` - (Optional) Whether vulnerability alerts are enabled for the repository. Defaults to `true`. + +## Import + +Repository vulnerability alerts can be imported using the `repository_owner:repository_name` format: + +```sh +terraform import github_repository_vulnerability_alerts.example my-org:my-repo +``` From 25f08a01a01d77336026c6dd148ae139ef872a3e Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sun, 8 Feb 2026 13:34:56 +0200 Subject: [PATCH 02/15] Mark `vulnerability_alerts` in `github_repository` as deprecated Signed-off-by: Timo Sand --- github/resource_github_repository.go | 3 ++- website/docs/r/repository.html.markdown | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 2c57b54182..514cbf7305 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -400,12 +400,13 @@ func resourceGithubRepository() *schema.Resource { Optional: true, Computed: true, Description: "Set to 'true' to enable security alerts for vulnerable dependencies. Enabling requires alerts to be enabled on the owner level. (Note for importing: GitHub enables the alerts on all repos by default). Note that vulnerability alerts have not been successfully tested on any GitHub Enterprise instance and may be unavailable in those settings.", + Deprecated: "Use the github_repository_vulnerability_alerts resource instead. This field will be removed in a future version.", }, "ignore_vulnerability_alerts_during_read": { Type: schema.TypeBool, Optional: true, Default: false, - Deprecated: "This is ignored as the provider now handles lack of permissions automatically.", + Deprecated: "This is ignored as the provider now handles lack of permissions automatically. This field will be removed in a future version.", }, "full_name": { Type: schema.TypeString, diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index 157fd01caa..be0fef95a7 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -140,9 +140,9 @@ initial repository creation and create the target branch inside of the repositor * `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. -* `vulnerability_alerts` - (Optional) Configure [Dependabot security alerts](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for vulnerable dependencies; set to `true` to enable, set to `false` to disable, and leave unset for the default behavior. Configuring this requires that alerts are not being explicitly configured at the organization level. +* `vulnerability_alerts` - (Optional) (**DEPRECATED**) Configure [Dependabot security alerts](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for vulnerable dependencies; set to `true` to enable, set to `false` to disable, and leave unset for the default behavior. Configuring this requires that alerts are not being explicitly configured at the organization level. This field will be removed in a future version. Use the `github_repository_vulnerability_alerts` resource instead. -* `ignore_vulnerability_alerts_during_read` (**DEPRECATED**) (Optional) - This is ignored as the provider now handles lack of permissions automatically. +* `ignore_vulnerability_alerts_during_read` (**DEPRECATED**) (Optional) - This is ignored as the provider now handles lack of permissions automatically. This field will be removed in a future version. * `allow_update_branch` (Optional) - Set to `true` to always suggest updating pull request branches. From 19d51d27d2214af240eb7a750a54f7542786791e Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sun, 8 Feb 2026 13:35:04 +0200 Subject: [PATCH 03/15] Update formatting Signed-off-by: Timo Sand --- website/docs/r/repository.html.markdown | 142 ++++++++++++------------ 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index be0fef95a7..182e98125d 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -63,156 +63,156 @@ resource "github_repository" "forked_repo" { The following arguments are supported: -* `name` - (Required) The name of the repository. +- `name` - (Required) The name of the repository. -* `description` - (Optional) A description of the repository. +- `description` - (Optional) A description of the repository. -* `homepage_url` - (Optional) URL of a page describing the project. +- `homepage_url` - (Optional) URL of a page describing the project. -* `fork` - (Optional) Set to `true` to create a fork of an existing repository. When set to `true`, both `source_owner` and `source_repo` must also be specified. +- `fork` - (Optional) Set to `true` to create a fork of an existing repository. When set to `true`, both `source_owner` and `source_repo` must also be specified. -* `source_owner` - (Optional) The GitHub username or organization that owns the repository being forked. Required when `fork` is `true`. +- `source_owner` - (Optional) The GitHub username or organization that owns the repository being forked. Required when `fork` is `true`. -* `source_repo` - (Optional) The name of the repository to fork. Required when `fork` is `true`. +- `source_repo` - (Optional) The name of the repository to fork. Required when `fork` is `true`. -* `private` - (Optional) Set to `true` to create a private repository. +- `private` - (Optional) Set to `true` to create a private repository. Repositories are created as public (e.g. open source) by default. -* `visibility` - (Optional) Can be `public` or `private`. If your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+, visibility can also be `internal`. The `visibility` parameter overrides the `private` parameter. +- `visibility` - (Optional) Can be `public` or `private`. If your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+, visibility can also be `internal`. The `visibility` parameter overrides the `private` parameter. -* `has_issues` - (Optional) Set to `true` to enable the GitHub Issues features +- `has_issues` - (Optional) Set to `true` to enable the GitHub Issues features on the repository. -* `has_discussions` - (Optional) Set to `true` to enable GitHub Discussions on the repository. Defaults to `false`. +- `has_discussions` - (Optional) Set to `true` to enable GitHub Discussions on the repository. Defaults to `false`. -* `has_projects` - (Optional) Set to `true` to enable the GitHub Projects features on the repository. Per the GitHub [documentation](https://developer.github.com/v3/repos/#create) when in an organization that has disabled repository projects it will default to `false` and will otherwise default to `true`. If you specify `true` when it has been disabled it will return an error. +- `has_projects` - (Optional) Set to `true` to enable the GitHub Projects features on the repository. Per the GitHub [documentation](https://developer.github.com/v3/repos/#create) when in an organization that has disabled repository projects it will default to `false` and will otherwise default to `true`. If you specify `true` when it has been disabled it will return an error. -* `has_wiki` - (Optional) Set to `true` to enable the GitHub Wiki features on +- `has_wiki` - (Optional) Set to `true` to enable the GitHub Wiki features on the repository. -* `is_template` - (Optional) Set to `true` to tell GitHub that this is a template repository. +- `is_template` - (Optional) Set to `true` to tell GitHub that this is a template repository. -* `allow_merge_commit` - (Optional) Set to `false` to disable merge commits on the repository. +- `allow_merge_commit` - (Optional) Set to `false` to disable merge commits on the repository. -* `allow_squash_merge` - (Optional) Set to `false` to disable squash merges on the repository. +- `allow_squash_merge` - (Optional) Set to `false` to disable squash merges on the repository. -* `allow_rebase_merge` - (Optional) Set to `false` to disable rebase merges on the repository. +- `allow_rebase_merge` - (Optional) Set to `false` to disable rebase merges on the repository. -* `allow_auto_merge` - (Optional) Set to `true` to allow auto-merging pull requests on the repository. +- `allow_auto_merge` - (Optional) Set to `true` to allow auto-merging pull requests on the repository. -* `allow_forking` - (Optional) Configure private forking for organization owned private and internal repositories; set to `true` to enable, `false` to disable, and leave unset for the default behaviour. Configuring this requires that private forking is not being explicitly configured at the organization level. +- `allow_forking` - (Optional) Configure private forking for organization owned private and internal repositories; set to `true` to enable, `false` to disable, and leave unset for the default behaviour. Configuring this requires that private forking is not being explicitly configured at the organization level. -* `squash_merge_commit_title` - (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if `allow_squash_merge` is `true`. +- `squash_merge_commit_title` - (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if `allow_squash_merge` is `true`. -* `squash_merge_commit_message` - (Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if `allow_squash_merge` is `true`. +- `squash_merge_commit_message` - (Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if `allow_squash_merge` is `true`. -* `merge_commit_title` - Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if `allow_merge_commit` is `true`. +- `merge_commit_title` - Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if `allow_merge_commit` is `true`. -* `merge_commit_message` - Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if `allow_merge_commit` is `true`. +- `merge_commit_message` - Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if `allow_merge_commit` is `true`. -* `delete_branch_on_merge` - (Optional) Automatically delete head branch after a pull request is merged. Defaults to `false`. +- `delete_branch_on_merge` - (Optional) Automatically delete head branch after a pull request is merged. Defaults to `false`. -* `web_commit_signoff_required` - (Optional) Require contributors to sign off on web-based commits. See more [here](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-the-commit-signoff-policy-for-your-repository). +- `web_commit_signoff_required` - (Optional) Require contributors to sign off on web-based commits. See more in the [GitHub documentation](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-the-commit-signoff-policy-for-your-repository). -* `has_downloads` - (**DEPRECATED**) (Optional) Set to `true` to enable the (deprecated) downloads features on the repository. This attribute is no longer in use, but it hasn't been removed yet. It will be removed in a future version. See [this discussion](https://github.com/orgs/community/discussions/102145#discussioncomment-8351756). +- `has_downloads` - (**DEPRECATED**) (Optional) Set to `true` to enable the (deprecated) downloads features on the repository. This attribute is no longer in use, but it hasn't been removed yet. It will be removed in a future version. See [this discussion](https://github.com/orgs/community/discussions/102145#discussioncomment-8351756). -* `auto_init` - (Optional) Set to `true` to produce an initial commit in the repository. +- `auto_init` - (Optional) Set to `true` to produce an initial commit in the repository. -* `gitignore_template` - (Optional) Use the [name of the template](https://github.com/github/gitignore) without the extension. For example, "Haskell". +- `gitignore_template` - (Optional) Use the [name of the template](https://github.com/github/gitignore) without the extension. For example, "Haskell". -* `license_template` - (Optional) Use the [name of the template](https://github.com/github/choosealicense.com/tree/gh-pages/_licenses) without the extension. For example, "mit" or "mpl-2.0". +- `license_template` - (Optional) Use the [name of the template](https://github.com/github/choosealicense.com/tree/gh-pages/_licenses) without the extension. For example, "mit" or "mpl-2.0". -* `default_branch` - (Optional) (Deprecated: Use `github_branch_default` resource instead) The name of the default branch of the repository. **NOTE:** This can only be set after a repository has already been created, +- `default_branch` - (Optional) (Deprecated: Use `github_branch_default` resource instead) The name of the default branch of the repository. **NOTE:** This can only be set after a repository has already been created, and after a correct reference has been created for the target branch inside the repository. This means a user will have to omit this parameter from the initial repository creation and create the target branch inside of the repository prior to setting this attribute. -* `archived` - (Optional) Specifies if the repository should be archived. Defaults to `false`. **NOTE** Currently, the API does not support unarchiving. +- `archived` - (Optional) Specifies if the repository should be archived. Defaults to `false`. **NOTE** Currently, the API does not support unarchiving. -* `archive_on_destroy` - (Optional) Set to `true` to archive the repository instead of deleting on destroy. +- `archive_on_destroy` - (Optional) Set to `true` to archive the repository instead of deleting on destroy. -* `pages` - (Optional) The repository's GitHub Pages configuration. See [GitHub Pages Configuration](#github-pages-configuration) below for details. +- `pages` - (Optional) The repository's GitHub Pages configuration. See [GitHub Pages Configuration](#github-pages-configuration) below for details. -* `security_and_analysis` - (Optional) The repository's [security and analysis](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository) configuration. See [Security and Analysis Configuration](#security-and-analysis-configuration) below for details. +- `security_and_analysis` - (Optional) The repository's [security and analysis](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository) configuration. See [Security and Analysis Configuration](#security-and-analysis-configuration) below for details. -* `topics` - (Optional) The list of topics of the repository. +- `topics` - (Optional) The list of topics of the repository. ~> Note: This attribute is not compatible with the `github_repository_topics` resource. Use one of them. `github_repository_topics` is only meant to be used if the repository itself is not handled via terraform, for example if it's only read as a datasource (see [issue #1845](https://github.com/integrations/terraform-provider-github/issues/1845)). -* `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. +- `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. -* `vulnerability_alerts` - (Optional) (**DEPRECATED**) Configure [Dependabot security alerts](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for vulnerable dependencies; set to `true` to enable, set to `false` to disable, and leave unset for the default behavior. Configuring this requires that alerts are not being explicitly configured at the organization level. This field will be removed in a future version. Use the `github_repository_vulnerability_alerts` resource instead. +- `vulnerability_alerts` - (Optional) (**DEPRECATED**) Configure [Dependabot security alerts](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for vulnerable dependencies; set to `true` to enable, set to `false` to disable, and leave unset for the default behavior. Configuring this requires that alerts are not being explicitly configured at the organization level. This field will be removed in a future version. Use the `github_repository_vulnerability_alerts` resource instead. -* `ignore_vulnerability_alerts_during_read` (**DEPRECATED**) (Optional) - This is ignored as the provider now handles lack of permissions automatically. This field will be removed in a future version. +- `ignore_vulnerability_alerts_during_read` (**DEPRECATED**) (Optional) - This is ignored as the provider now handles lack of permissions automatically. This field will be removed in a future version. -* `allow_update_branch` (Optional) - Set to `true` to always suggest updating pull request branches. +- `allow_update_branch` (Optional) - Set to `true` to always suggest updating pull request branches. ### GitHub Pages Configuration The `pages` block supports the following: -* `source` - (Optional) The source branch and directory for the rendered Pages site. See [GitHub Pages Source](#github-pages-source) below for details. +- `source` - (Optional) The source branch and directory for the rendered Pages site. See [GitHub Pages Source](#github-pages-source) below for details. -* `build_type` - (Optional) The type of GitHub Pages site to build. Can be `legacy` or `workflow`. If you use `legacy` as build type you need to set the option `source`. +- `build_type` - (Optional) The type of GitHub Pages site to build. Can be `legacy` or `workflow`. If you use `legacy` as build type you need to set the option `source`. -* `cname` - (Optional) The custom domain for the repository. This can only be set after the repository has been created. +- `cname` - (Optional) The custom domain for the repository. This can only be set after the repository has been created. #### GitHub Pages Source The `source` block supports the following: -* `branch` - (Required) The repository branch used to publish the site's source files. (i.e. `main` or `gh-pages`. +- `branch` - (Required) The repository branch used to publish the site's source files. (i.e. `main` or `gh-pages`. -* `path` - (Optional) The repository directory from which the site publishes (Default: `/`). +- `path` - (Optional) The repository directory from which the site publishes (Default: `/`). ### Security and Analysis Configuration The `security_and_analysis` block supports the following: -* `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. If a repository's visibility is `public`, advanced security is always enabled and cannot be changed, so this setting cannot be supplied. +- `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. If a repository's visibility is `public`, advanced security is always enabled and cannot be changed, so this setting cannot be supplied. -* `code_security` - (Optional) The code security configuration for the repository. See [Code Security](#code-security-configuration) below for details. +- `code_security` - (Optional) The code security configuration for the repository. See [Code Security](#code-security-configuration) below for details. -* `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. +- `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. -* `secret_scanning_push_protection` - (Optional) The secret scanning push protection configuration for the repository. See [Secret Scanning Push Protection Configuration](#secret-scanning-push-protection-configuration) below for details. +- `secret_scanning_push_protection` - (Optional) The secret scanning push protection configuration for the repository. See [Secret Scanning Push Protection Configuration](#secret-scanning-push-protection-configuration) below for details. -* `secret_scanning_ai_detection` - (Optional) The secret scanning ai detection configuration for the repository. See [Secret Scanning AI Detection Configuration](#secret-scanning-ai-detection-configuration) below for details. +- `secret_scanning_ai_detection` - (Optional) The secret scanning ai detection configuration for the repository. See [Secret Scanning AI Detection Configuration](#secret-scanning-ai-detection) below for details. -* `secret_scanning_non_provider_patterns` - (Optional) The secret scanning non-provider patterns configuration for this repository. See [Secret Scanning Non-Provider Patterns Configuration](#secret-scanning-non-provider-patterns-configuration) below for more details. +- `secret_scanning_non_provider_patterns` - (Optional) The secret scanning non-provider patterns configuration for this repository. See [Secret Scanning Non-Provider Patterns Configuration](#secret-scanning-non-provider-patterns) below for more details. #### Advanced Security Configuration The `advanced_security` block supports the following: -* `status` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. +- `status` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. #### Code Security Configuration -* `status` - (Required) Set to `enabled` to enable GitHub Code Security on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable GitHub Code Security on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Configuration -* `status` - (Required) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Push Protection Configuration -* `status` - (Required) Set to `enabled` to enable secret scanning push protection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning push protection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning AI Detection -* `status` - (Required) Set to `enabled` to enable secret scanning AI detection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning AI detection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Non-Provider Patterns -* `status` - (Required) Set to `enabled` to enable secret scanning non-provider patterns on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning non-provider patterns on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. ### Template Repositories `template` supports the following arguments: -* `owner`: The GitHub organization or user the template repository is owned by. -* `repository`: The name of the template repository. -* `include_all_branches`: Whether the new repository should include all the branches from the template repository (defaults to false, which includes only the default branch from the template). +- `owner`: The GitHub organization or user the template repository is owned by. +- `repository`: The name of the template repository. +- `include_all_branches`: Whether the new repository should include all the branches from the template repository (defaults to false, which includes only the default branch from the template). ~> **Note on `internal` visibility with templates**: When creating a repository from a template with `visibility = "internal"`, the provider uses a two-step process due to GitHub API limitations. The template creation API only supports a `private` boolean parameter. Therefore, repositories with `visibility = "internal"` are initially created as private and then immediately updated to internal visibility. This ensures internal repositories are never exposed publicly during creation. @@ -220,28 +220,28 @@ The `advanced_security` block supports the following: The following additional attributes are exported: -* `full_name` - A string of the form "orgname/reponame". +- `full_name` - A string of the form "orgname/reponame". -* `html_url` - URL to the repository on the web. +- `html_url` - URL to the repository on the web. -* `ssh_clone_url` - URL that can be provided to `git clone` to clone the repository via SSH. +- `ssh_clone_url` - URL that can be provided to `git clone` to clone the repository via SSH. -* `http_clone_url` - URL that can be provided to `git clone` to clone the repository via HTTPS. +- `http_clone_url` - URL that can be provided to `git clone` to clone the repository via HTTPS. -* `git_clone_url` - URL that can be provided to `git clone` to clone the repository anonymously via the git protocol. +- `git_clone_url` - URL that can be provided to `git clone` to clone the repository anonymously via the git protocol. -* `svn_url` - URL that can be provided to `svn checkout` to check out the repository via GitHub's Subversion protocol emulation. +- `svn_url` - URL that can be provided to `svn checkout` to check out the repository via GitHub's Subversion protocol emulation. -* `node_id` - GraphQL global node id for use with v4 API +- `node_id` - GraphQL global node id for use with v4 API -* `repo_id` - GitHub ID for the repository +- `repo_id` - GitHub ID for the repository -* `primary_language` - The primary language used in the repository. +- `primary_language` - The primary language used in the repository. -* `pages` - The block consisting of the repository's GitHub Pages configuration with the following additional attributes: -* `custom_404` - Whether the rendered GitHub Pages site has a custom 404 page. -* `html_url` - The absolute URL (including scheme) of the rendered GitHub Pages site e.g. `https://username.github.io`. -* `status` - The GitHub Pages site's build status e.g. `building` or `built`. +- `pages` - The block consisting of the repository's GitHub Pages configuration with the following additional attributes: +- `custom_404` - Whether the rendered GitHub Pages site has a custom 404 page. +- `html_url` - The absolute URL (including scheme) of the rendered GitHub Pages site e.g. `https://username.github.io`. +- `status` - The GitHub Pages site's build status e.g. `building` or `built`. ## Import From 804a963039cbb2fcd2b9ac85c58316a37bc45dc9 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 14 Feb 2026 00:57:08 +0200 Subject: [PATCH 04/15] Update import after rebase Signed-off-by: Timo Sand --- github/github_repository_vulnerability_alerts_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github/github_repository_vulnerability_alerts_test.go b/github/github_repository_vulnerability_alerts_test.go index f4710b6b5c..25334f441f 100644 --- a/github/github_repository_vulnerability_alerts_test.go +++ b/github/github_repository_vulnerability_alerts_test.go @@ -4,8 +4,8 @@ import ( "fmt" "testing" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" ) func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { From 0019c57aebf732c9d51d3b301730ee777c4259ce Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Mon, 16 Feb 2026 21:47:31 +0200 Subject: [PATCH 05/15] Correct file names Signed-off-by: Timo Sand --- ...erts.go => resource_github_repository_vulnerability_alerts.go} | 0 ...go => resource_github_repository_vulnerability_alerts_test.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename github/{github_repository_vulnerability_alerts.go => resource_github_repository_vulnerability_alerts.go} (100%) rename github/{github_repository_vulnerability_alerts_test.go => resource_github_repository_vulnerability_alerts_test.go} (100%) diff --git a/github/github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go similarity index 100% rename from github/github_repository_vulnerability_alerts.go rename to github/resource_github_repository_vulnerability_alerts.go diff --git a/github/github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go similarity index 100% rename from github/github_repository_vulnerability_alerts_test.go rename to github/resource_github_repository_vulnerability_alerts_test.go From 5351829836a8ffd9fb5454ac19cd762491284c9a Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Mon, 16 Feb 2026 23:12:43 +0200 Subject: [PATCH 06/15] Address review comments Signed-off-by: Timo Sand --- ..._github_repository_vulnerability_alerts.go | 61 ++++++++++++++----- ...ub_repository_vulnerability_alerts_test.go | 43 +++++++++---- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index d9e4559cd0..0dfe494a77 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -3,7 +3,9 @@ package github import ( "context" "fmt" + "strconv" + "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -19,13 +21,18 @@ func resourceGithubRepositoryVulnerabilityAlerts() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "repository_name": { + "repository": { Type: schema.TypeString, Required: true, ForceNew: true, Description: "The repository name to configure vulnerability alerts for.", }, - "repository_owner": { + "repository_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The ID of the repository to configure vulnerability alerts for.", + }, + "owner": { Type: schema.TypeString, Required: true, ForceNew: true, @@ -38,6 +45,8 @@ func resourceGithubRepositoryVulnerabilityAlerts() *schema.Resource { Description: "Whether vulnerability alerts are enabled for the repository.", }, }, + + CustomizeDiff: diffRepository, } } @@ -45,8 +54,8 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("repository_owner").(string) - repoName := d.Get("repository_name").(string) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled := d.Get("enabled").(bool) if vulnerabilityAlertsEnabled { @@ -60,8 +69,15 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s return diag.FromErr(err) } } + repo, _, err := client.Repositories.Get(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("repository_id", repo.GetID()); err != nil { + return diag.FromErr(err) + } - id, err := buildID(owner, repoName) + id, err := buildID(owner, strconv.Itoa(int(repo.GetID()))) if err != nil { return diag.FromErr(err) } @@ -74,8 +90,8 @@ func resourceGithubRepositoryVulnerabilityAlertsRead(ctx context.Context, d *sch meta := m.(*Owner) client := meta.v3client - owner := d.Get("repository_owner").(string) - repoName := d.Get("repository_name").(string) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled, _, err := client.Repositories.GetVulnerabilityAlerts(ctx, owner, repoName) if err != nil { return diag.Errorf("error reading repository vulnerability alerts: %s", err.Error()) @@ -91,8 +107,8 @@ func resourceGithubRepositoryVulnerabilityAlertsUpdate(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("repository_owner").(string) - repoName := d.Get("repository_name").(string) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled := d.Get("enabled").(bool) if vulnerabilityAlertsEnabled { @@ -114,8 +130,8 @@ func resourceGithubRepositoryVulnerabilityAlertsDelete(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("repository_owner").(string) - repoName := d.Get("repository_name").(string) + owner := d.Get("owner").(string) + repoName := d.Get("repository").(string) _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { return diag.FromErr(handleArchivedRepoDelete(err, "repository vulnerability alerts", d.Id(), owner, repoName)) @@ -124,22 +140,35 @@ func resourceGithubRepositoryVulnerabilityAlertsDelete(ctx context.Context, d *s return nil } -func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { +func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { + tflog.Debug(ctx, "Importing repository vulnerability alerts", map[string]any{"id": d.Id()}) repoOwner, repoName, err := parseID2(d.Id()) if err != nil { - return nil, fmt.Errorf("invalid ID specified: supplied ID must be written as /. Original error: %w", err) + return nil, fmt.Errorf("invalid ID specified: supplied ID must be written as :. Original error: %w", err) } - if err := d.Set("repository_owner", repoOwner); err != nil { + if err := d.Set("owner", repoOwner); err != nil { return nil, err } - if err := d.Set("repository_name", repoName); err != nil { + if err := d.Set("repository", repoName); err != nil { return nil, err } - id, err := buildID(repoOwner, repoName) + meta := m.(*Owner) + client := meta.v3client + + repo, _, err := client.Repositories.Get(ctx, repoOwner, repoName) + if err != nil { + return nil, err + } + if err = d.Set("repository_id", repo.GetID()); err != nil { + return nil, err + } + + id, err := buildID(repoOwner, strconv.Itoa(int(repo.GetID()))) if err != nil { return nil, err } + d.SetId(id) return []*schema.ResourceData{d}, nil diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index 25334f441f..0eba4a82c7 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" ) func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { @@ -21,8 +22,8 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository_name = github_repository.test.name - repository_owner = "%s" + repository = github_repository.test.name + owner = "%s" enabled = true } `, repoName, testAccConf.owner) @@ -35,7 +36,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { Config: config, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "repository_name", repoName), + resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "repository", repoName), ), }, }, @@ -54,8 +55,8 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository_name = github_repository.test.name - repository_owner = "%s" + repository = github_repository.test.name + owner = "%s" enabled = false } `, repoName, testAccConf.owner) @@ -88,8 +89,8 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository_name = github_repository.test.name - repository_owner = "%s" + repository = github_repository.test.name + owner = "%s" enabled = %t } ` @@ -128,8 +129,8 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository_name = github_repository.test.name - repository_owner = "%s" + repository = github_repository.test.name + owner = "%s" enabled = %t } ` @@ -166,8 +167,8 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository_name = github_repository.test.name - repository_owner = "%s" + repository = github_repository.test.name + owner = "%s" enabled = true } `, repoName, testAccConf.owner) @@ -186,6 +187,26 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { ResourceName: "github_repository_vulnerability_alerts.test", ImportState: true, ImportStateVerify: true, + ImportStateIdFunc: func(state *terraform.State) (string, error) { + vulnerabilityAlerts := state.RootModule().Resources["github_repository_vulnerability_alerts.test"] + if vulnerabilityAlerts == nil { + return "", fmt.Errorf("github_repository_vulnerability_alerts.test not found in state") + } + vulnerabilityAlertsID := vulnerabilityAlerts.Primary.ID + if vulnerabilityAlertsID == "" { + return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have an id in state") + } + owner, found := vulnerabilityAlerts.Primary.Attributes["owner"] + if !found { + return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have an owner in state") + } + repository, found := vulnerabilityAlerts.Primary.Attributes["repository"] + if !found { + return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have a repository in state") + } + return fmt.Sprintf("%s:%s", owner, repository), nil + }, + ImportStateVerifyIgnore: []string{"enabled"}, }, }, }) From cf518f45943017cdb6fbfc76fb876701d63772c7 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Tue, 17 Feb 2026 22:14:55 +0200 Subject: [PATCH 07/15] Simplify `SetId` Signed-off-by: Timo Sand --- ...source_github_repository_vulnerability_alerts.go | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index 0dfe494a77..527552fcae 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -77,11 +77,7 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s return diag.FromErr(err) } - id, err := buildID(owner, strconv.Itoa(int(repo.GetID()))) - if err != nil { - return diag.FromErr(err) - } - d.SetId(id) + d.SetId(strconv.Itoa(int(repo.GetID()))) return nil } @@ -164,12 +160,7 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s return nil, err } - id, err := buildID(repoOwner, strconv.Itoa(int(repo.GetID()))) - if err != nil { - return nil, err - } - - d.SetId(id) + d.SetId(strconv.Itoa(int(repo.GetID()))) return []*schema.ResourceData{d}, nil } From 0ca677eee5077b6eaffca5012a7d224ca153d547 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Tue, 17 Feb 2026 22:19:47 +0200 Subject: [PATCH 08/15] Comment out `owner` until we can support it better Signed-off-by: Timo Sand --- ..._github_repository_vulnerability_alerts.go | 27 ++++----- ...ub_repository_vulnerability_alerts_test.go | 56 +++++-------------- 2 files changed, 29 insertions(+), 54 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index 527552fcae..c9c8a502a6 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -32,12 +32,13 @@ func resourceGithubRepositoryVulnerabilityAlerts() *schema.Resource { Computed: true, Description: "The ID of the repository to configure vulnerability alerts for.", }, - "owner": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - Description: "The owner of the repository to configure vulnerability alerts for.", - }, + // TODO: Uncomment this when we are ready to support owner fields properly. https://github.com/integrations/terraform-provider-github/pull/3166#discussion_r2816053082 + // "owner": { + // Type: schema.TypeString, + // Required: true, + // ForceNew: true, + // Description: "The owner of the repository to configure vulnerability alerts for.", + // }, "enabled": { Type: schema.TypeBool, Optional: true, @@ -54,7 +55,7 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("owner").(string) + owner := meta.name // TODO: Add owner support // d.Get("owner").(string) repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled := d.Get("enabled").(bool) @@ -86,7 +87,7 @@ func resourceGithubRepositoryVulnerabilityAlertsRead(ctx context.Context, d *sch meta := m.(*Owner) client := meta.v3client - owner := d.Get("owner").(string) + owner := meta.name // TODO: Add owner support // d.Get("owner").(string) repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled, _, err := client.Repositories.GetVulnerabilityAlerts(ctx, owner, repoName) if err != nil { @@ -103,7 +104,7 @@ func resourceGithubRepositoryVulnerabilityAlertsUpdate(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("owner").(string) + owner := meta.name // TODO: Add owner support // d.Get("owner").(string) repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled := d.Get("enabled").(bool) @@ -126,7 +127,7 @@ func resourceGithubRepositoryVulnerabilityAlertsDelete(ctx context.Context, d *s meta := m.(*Owner) client := meta.v3client - owner := d.Get("owner").(string) + owner := meta.name // TODO: Add owner support // d.Get("owner").(string) repoName := d.Get("repository").(string) _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { @@ -142,9 +143,9 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s if err != nil { return nil, fmt.Errorf("invalid ID specified: supplied ID must be written as :. Original error: %w", err) } - if err := d.Set("owner", repoOwner); err != nil { - return nil, err - } + // if err := d.Set("owner", repoOwner); err != nil { // TODO: Add owner support + // return nil, err + // } if err := d.Set("repository", repoName); err != nil { return nil, err } diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index 0eba4a82c7..e90379ae3b 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -6,7 +6,6 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/hashicorp/terraform-plugin-testing/terraform" ) func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { @@ -23,10 +22,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - owner = "%s" - enabled = true + enabled = true } - `, repoName, testAccConf.owner) + `, repoName) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, @@ -56,10 +54,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - owner = "%s" - enabled = false + enabled = false } - `, repoName, testAccConf.owner) + `, repoName) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, @@ -90,8 +87,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - owner = "%s" - enabled = %t + enabled = %t } ` @@ -100,13 +96,13 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(config, repoName, testAccConf.owner, enabled), + Config: fmt.Sprintf(config, repoName, enabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), ), }, { - Config: fmt.Sprintf(config, repoName, testAccConf.owner, updatedEnabled), + Config: fmt.Sprintf(config, repoName, updatedEnabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), ), @@ -130,8 +126,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - owner = "%s" - enabled = %t + enabled = %t } ` @@ -140,13 +135,13 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(config, repoName, testAccConf.owner, enabled), + Config: fmt.Sprintf(config, repoName, enabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), ), }, { - Config: fmt.Sprintf(config, repoName, testAccConf.owner, updatedEnabled), + Config: fmt.Sprintf(config, repoName, updatedEnabled), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), ), @@ -168,10 +163,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - owner = "%s" - enabled = true + enabled = true } - `, repoName, testAccConf.owner) + `, repoName) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, @@ -184,29 +178,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { ), }, { - ResourceName: "github_repository_vulnerability_alerts.test", - ImportState: true, - ImportStateVerify: true, - ImportStateIdFunc: func(state *terraform.State) (string, error) { - vulnerabilityAlerts := state.RootModule().Resources["github_repository_vulnerability_alerts.test"] - if vulnerabilityAlerts == nil { - return "", fmt.Errorf("github_repository_vulnerability_alerts.test not found in state") - } - vulnerabilityAlertsID := vulnerabilityAlerts.Primary.ID - if vulnerabilityAlertsID == "" { - return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have an id in state") - } - owner, found := vulnerabilityAlerts.Primary.Attributes["owner"] - if !found { - return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have an owner in state") - } - repository, found := vulnerabilityAlerts.Primary.Attributes["repository"] - if !found { - return "", fmt.Errorf("github_repository_vulnerability_alerts.test does not have a repository in state") - } - return fmt.Sprintf("%s:%s", owner, repository), nil - }, - ImportStateVerifyIgnore: []string{"enabled"}, + ResourceName: "github_repository_vulnerability_alerts.test", + ImportState: true, + ImportStateId: fmt.Sprintf("%s:%s", testAccConf.owner, repoName), }, }, }) From dfe973217cf9928427a8b4515939ea24be2ff087 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Tue, 17 Feb 2026 22:34:43 +0200 Subject: [PATCH 09/15] Refactor to use `ConfigStateChecks` Signed-off-by: Timo Sand --- ...ub_repository_vulnerability_alerts_test.go | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index e90379ae3b..148c43f13e 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -4,8 +4,12 @@ import ( "fmt" "testing" + "github.com/hashicorp/terraform-plugin-testing/compare" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { @@ -32,10 +36,11 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "repository", repoName), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled"), knownvalue.Bool(true)), + statecheck.CompareValuePairs("github_repository_vulnerability_alerts.test", tfjsonpath.New("repository"), "github_repository.test", tfjsonpath.New("name"), compare.ValuesSame()), + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + }, }, }, }) @@ -64,9 +69,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled"), knownvalue.Bool(false)), + }, }, }, }) @@ -91,21 +96,23 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } ` + compareValuesDiffer := statecheck.CompareValue(compare.ValuesDiffer()) + resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: fmt.Sprintf(config, repoName, enabled), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + }, }, { Config: fmt.Sprintf(config, repoName, updatedEnabled), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + }, }, }, }) @@ -130,21 +137,23 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } ` + compareValuesDiffer := statecheck.CompareValue(compare.ValuesDiffer()) + resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: fmt.Sprintf(config, repoName, enabled), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + }, }, { Config: fmt.Sprintf(config, repoName, updatedEnabled), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "false"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + }, }, }, }) @@ -173,9 +182,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_repository_vulnerability_alerts.test", "enabled", "true"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + }, }, { ResourceName: "github_repository_vulnerability_alerts.test", From a0da2e7db6e7a22754480c67f073e22f6c589e3c Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 13:41:39 +0200 Subject: [PATCH 10/15] Update import ID to only repository name Signed-off-by: Timo Sand --- ...resource_github_repository_vulnerability_alerts.go | 9 +++------ ...rce_github_repository_vulnerability_alerts_test.go | 2 +- .../r/repository_vulnerability_alerts.html.markdown | 11 ++++------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index c9c8a502a6..f4d220440c 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -2,7 +2,6 @@ package github import ( "context" - "fmt" "strconv" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -139,10 +138,7 @@ func resourceGithubRepositoryVulnerabilityAlertsDelete(ctx context.Context, d *s func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { tflog.Debug(ctx, "Importing repository vulnerability alerts", map[string]any{"id": d.Id()}) - repoOwner, repoName, err := parseID2(d.Id()) - if err != nil { - return nil, fmt.Errorf("invalid ID specified: supplied ID must be written as :. Original error: %w", err) - } + repoName := d.Id() // if err := d.Set("owner", repoOwner); err != nil { // TODO: Add owner support // return nil, err // } @@ -151,9 +147,10 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s } meta := m.(*Owner) + owner := meta.name client := meta.v3client - repo, _, err := client.Repositories.Get(ctx, repoOwner, repoName) + repo, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { return nil, err } diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index 148c43f13e..c5c6aad69e 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -189,7 +189,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { { ResourceName: "github_repository_vulnerability_alerts.test", ImportState: true, - ImportStateId: fmt.Sprintf("%s:%s", testAccConf.owner, repoName), + ImportStateId: repoName, }, }, }) diff --git a/website/docs/r/repository_vulnerability_alerts.html.markdown b/website/docs/r/repository_vulnerability_alerts.html.markdown index d09b23495b..162a8c0a62 100644 --- a/website/docs/r/repository_vulnerability_alerts.html.markdown +++ b/website/docs/r/repository_vulnerability_alerts.html.markdown @@ -21,8 +21,7 @@ resource "github_repository" "example" { } resource "github_repository_vulnerability_alerts" "example" { - repository_owner = "my-org" - repository_name = github_repository.example.name + repository = github_repository.example.name enabled = true } ``` @@ -31,16 +30,14 @@ resource "github_repository_vulnerability_alerts" "example" { The following arguments are supported: -- `repository_owner` - (Required) The owner of the repository to configure vulnerability alerts for. - -- `repository_name` - (Required) The name of the repository to configure vulnerability alerts for. +- `repository` - (Required) The name of the repository to configure vulnerability alerts for. - `enabled` - (Optional) Whether vulnerability alerts are enabled for the repository. Defaults to `true`. ## Import -Repository vulnerability alerts can be imported using the `repository_owner:repository_name` format: +Repository vulnerability alerts can be imported using the `repository_name`: ```sh -terraform import github_repository_vulnerability_alerts.example my-org:my-repo +terraform import github_repository_vulnerability_alerts.example my-repo ``` From f0e94ed5674dc58dbc92e42d1ea73c20c69d567e Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 16:08:14 +0200 Subject: [PATCH 11/15] Improves tests Signed-off-by: Timo Sand --- ...ub_repository_vulnerability_alerts_test.go | 138 ++++++++++++++---- 1 file changed, 110 insertions(+), 28 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index c5c6aad69e..1a1d56c40c 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -8,12 +8,13 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { - t.Run("enables_vulnerability_alerts_without_error", func(t *testing.T) { + t.Run("creates_vulnerability_alerts_as_enabled_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) @@ -46,7 +47,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { }) }) - t.Run("disables_vulnerability_alerts_without_error", func(t *testing.T) { + t.Run("creates_vulnerability_alerts_as_disabled_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) @@ -77,11 +78,9 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { }) }) - t.Run("updates_vulnerability_alerts_from_disabled_to_enabled", func(t *testing.T) { + t.Run("updates_vulnerability_alerts_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) - enabled := false - updatedEnabled := true config := ` resource "github_repository" "test" { @@ -103,13 +102,19 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(config, repoName, enabled), + Config: fmt.Sprintf(config, repoName, false), ConfigStateChecks: []statecheck.StateCheck{ compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), }, }, { - Config: fmt.Sprintf(config, repoName, updatedEnabled), + Config: fmt.Sprintf(config, repoName, true), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + }, + }, + { + Config: fmt.Sprintf(config, repoName, false), ConfigStateChecks: []statecheck.StateCheck{ compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), }, @@ -118,13 +123,11 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { }) }) - t.Run("updates_vulnerability_alerts_from_enabled_to_disabled", func(t *testing.T) { + t.Run("imports_vulnerability_alerts_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) - enabled := true - updatedEnabled := false - config := ` + config := fmt.Sprintf(` resource "github_repository" "test" { name = "%s" visibility = "private" @@ -133,33 +136,31 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { resource "github_repository_vulnerability_alerts" "test" { repository = github_repository.test.name - enabled = %t + enabled = true } - ` - - compareValuesDiffer := statecheck.CompareValue(compare.ValuesDiffer()) + `, repoName) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: fmt.Sprintf(config, repoName, enabled), + Config: config, ConfigStateChecks: []statecheck.StateCheck{ - compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), }, }, { - Config: fmt.Sprintf(config, repoName, updatedEnabled), - ConfigStateChecks: []statecheck.StateCheck{ - compareValuesDiffer.AddStateValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled")), - }, + ResourceName: "github_repository_vulnerability_alerts.test", + ImportState: true, + ImportStateId: repoName, + ImportStateVerify: true, }, }, }) }) - t.Run("imports_vulnerability_alerts_without_error", func(t *testing.T) { + t.Run("creates_with_defaults_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) @@ -171,8 +172,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { } resource "github_repository_vulnerability_alerts" "test" { - repository = github_repository.test.name - enabled = true + repository = github_repository.test.name } `, repoName) @@ -183,13 +183,95 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { { Config: config, ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled"), knownvalue.Bool(true)), + }, + }, + }, + }) + }) + + t.Run("destroys_from_archived_repository_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + withAlertsConfig := ` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + archived = %t + } + + resource "github_repository_vulnerability_alerts" "test" { + repository = github_repository.test.name + enabled = true + } + ` + + archivedOnlyConfig := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + archived = true + } + `, repoName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(withAlertsConfig, repoName, false), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled"), knownvalue.Bool(true)), + }, + }, + { + Config: fmt.Sprintf(withAlertsConfig, repoName, true), + ExpectNonEmptyPlan: true, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository.test", tfjsonpath.New("archived"), knownvalue.Bool(true)), }, }, { - ResourceName: "github_repository_vulnerability_alerts.test", - ImportState: true, - ImportStateId: repoName, + Config: archivedOnlyConfig, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("github_repository_vulnerability_alerts.test", plancheck.ResourceActionDestroy), + }, + }, + }, + }, + }) + }) + + t.Run("creates_on_public_repo_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + visibility = "public" + auto_init = true + } + + resource "github_repository_vulnerability_alerts" "test" { + repository = github_repository.test.name + enabled = true + } + `, repoName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t); skipIfEMUEnterprise(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_repository_vulnerability_alerts.test", tfjsonpath.New("enabled"), knownvalue.Bool(true)), + }, }, }, }) From 569224bf61ba40f63d3ed573cc48fe8b87169746 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 16:08:38 +0200 Subject: [PATCH 12/15] Updates docs Signed-off-by: Timo Sand --- .../r/repository_vulnerability_alerts.html.markdown | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/website/docs/r/repository_vulnerability_alerts.html.markdown b/website/docs/r/repository_vulnerability_alerts.html.markdown index 162a8c0a62..cb047819d0 100644 --- a/website/docs/r/repository_vulnerability_alerts.html.markdown +++ b/website/docs/r/repository_vulnerability_alerts.html.markdown @@ -21,8 +21,8 @@ resource "github_repository" "example" { } resource "github_repository_vulnerability_alerts" "example" { - repository = github_repository.example.name - enabled = true + repository = github_repository.example.name + enabled = true } ``` @@ -34,6 +34,12 @@ The following arguments are supported: - `enabled` - (Optional) Whether vulnerability alerts are enabled for the repository. Defaults to `true`. +## Attribute Reference + +In addition to the above arguments, the following attributes are exported: + +- `repository_id` - The ID of the repository. + ## Import Repository vulnerability alerts can be imported using the `repository_name`: From 447bb031032477f40712a824b4e8875ad9ddee25 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 16:10:24 +0200 Subject: [PATCH 13/15] Add clearer error for user when trying to add to an archived repository Signed-off-by: Timo Sand --- ..._github_repository_vulnerability_alerts.go | 24 +++++++++-- ...ub_repository_vulnerability_alerts_test.go | 40 +++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index f4d220440c..84b8b25c32 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -2,8 +2,13 @@ package github import ( "context" + "errors" + "fmt" + "net/http" "strconv" + "strings" + "github.com/google/go-github/v83/github" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -59,14 +64,14 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s vulnerabilityAlertsEnabled := d.Get("enabled").(bool) if vulnerabilityAlertsEnabled { - _, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) + resp, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { - return diag.FromErr(err) + return diag.FromErr(handleVulnerabilityAlertsErrorOnArchivedRepository(err, resp, repoName)) } } else { - _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) + resp, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { - return diag.FromErr(err) + return diag.FromErr(handleVulnerabilityAlertsErrorOnArchivedRepository(err, resp, repoName)) } } repo, _, err := client.Repositories.Get(ctx, owner, repoName) @@ -162,3 +167,14 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s return []*schema.ResourceData{d}, nil } + +func handleVulnerabilityAlertsErrorOnArchivedRepository(err error, resp *github.Response, repoName string) error { + var ghErr *github.ErrorResponse + if errors.As(err, &ghErr) { + // Error response when trying to enable vulnerability alerts on an archived repository. "422 Failed to change dependabot alerts status" + if resp.StatusCode == http.StatusUnprocessableEntity && strings.Contains(strings.ToLower(ghErr.Message), "failed to change dependabot alerts status") { + return fmt.Errorf("failed to change vulnerability alerts for repository %s. The repository is most likely archived: %s", repoName, ghErr.Message) + } + } + return err +} diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index 1a1d56c40c..01058b9a88 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -2,6 +2,7 @@ package github import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-testing/compare" @@ -246,6 +247,45 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { }) }) + t.Run("creates_on_archived_repository_with_error)", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) + + repoConfig := ` + resource "github_repository" "test" { + name = "%s" + visibility = "private" + auto_init = true + archived = %t + } + %s + ` + + alertsBlock := ` + resource "github_repository_vulnerability_alerts" "test" { + repository = github_repository.test.name + enabled = true + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(repoConfig, repoName, false, ""), + }, + { + Config: fmt.Sprintf(repoConfig, repoName, true, ""), + }, + { + Config: fmt.Sprintf(repoConfig, repoName, true, alertsBlock), + ExpectError: regexp.MustCompile(`repository is most likely archived`), + }, + }, + }) + }) + t.Run("creates_on_public_repo_without_error", func(t *testing.T) { randomID := acctest.RandString(5) repoName := fmt.Sprintf("%svuln-alerts-%s", testResourcePrefix, randomID) From 4f3c3921568b7b54cd6858268ead25d0b820ba44 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Mon, 23 Feb 2026 20:51:20 +0200 Subject: [PATCH 14/15] Re-order `SetId` Signed-off-by: Timo Sand --- ...resource_github_repository_vulnerability_alerts.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index 84b8b25c32..b3855b5751 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -78,12 +78,13 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s if err != nil { return diag.FromErr(err) } + + d.SetId(strconv.Itoa(int(repo.GetID()))) + if err = d.Set("repository_id", repo.GetID()); err != nil { return diag.FromErr(err) } - d.SetId(strconv.Itoa(int(repo.GetID()))) - return nil } @@ -159,12 +160,12 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s if err != nil { return nil, err } - if err = d.Set("repository_id", repo.GetID()); err != nil { - return nil, err - } d.SetId(strconv.Itoa(int(repo.GetID()))) + if err = d.Set("repository_id", repo.GetID()); err != nil { + return nil, err + } return []*schema.ResourceData{d}, nil } From c41ad75269c91ff2169ae8ae60d6343142f2b10b Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Tue, 24 Feb 2026 21:19:08 +0200 Subject: [PATCH 15/15] Simplify archived repo handling Signed-off-by: Timo Sand --- ..._github_repository_vulnerability_alerts.go | 35 ++++++------------- ...ub_repository_vulnerability_alerts_test.go | 2 +- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/github/resource_github_repository_vulnerability_alerts.go b/github/resource_github_repository_vulnerability_alerts.go index b3855b5751..2cf7248db2 100644 --- a/github/resource_github_repository_vulnerability_alerts.go +++ b/github/resource_github_repository_vulnerability_alerts.go @@ -2,13 +2,8 @@ package github import ( "context" - "errors" - "fmt" - "net/http" "strconv" - "strings" - "github.com/google/go-github/v83/github" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -63,21 +58,24 @@ func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *s repoName := d.Get("repository").(string) vulnerabilityAlertsEnabled := d.Get("enabled").(bool) + repo, _, err := client.Repositories.Get(ctx, owner, repoName) + if err != nil { + return diag.FromErr(err) + } + if repo.GetArchived() { + return diag.Errorf("cannot enable vulnerability alerts on archived repository %s/%s", owner, repoName) + } if vulnerabilityAlertsEnabled { - resp, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) + _, err := client.Repositories.EnableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { - return diag.FromErr(handleVulnerabilityAlertsErrorOnArchivedRepository(err, resp, repoName)) + return diag.FromErr(err) } } else { - resp, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) + _, err := client.Repositories.DisableVulnerabilityAlerts(ctx, owner, repoName) if err != nil { - return diag.FromErr(handleVulnerabilityAlertsErrorOnArchivedRepository(err, resp, repoName)) + return diag.FromErr(err) } } - repo, _, err := client.Repositories.Get(ctx, owner, repoName) - if err != nil { - return diag.FromErr(err) - } d.SetId(strconv.Itoa(int(repo.GetID()))) @@ -168,14 +166,3 @@ func resourceGithubRepositoryVulnerabilityAlertsImport(ctx context.Context, d *s } return []*schema.ResourceData{d}, nil } - -func handleVulnerabilityAlertsErrorOnArchivedRepository(err error, resp *github.Response, repoName string) error { - var ghErr *github.ErrorResponse - if errors.As(err, &ghErr) { - // Error response when trying to enable vulnerability alerts on an archived repository. "422 Failed to change dependabot alerts status" - if resp.StatusCode == http.StatusUnprocessableEntity && strings.Contains(strings.ToLower(ghErr.Message), "failed to change dependabot alerts status") { - return fmt.Errorf("failed to change vulnerability alerts for repository %s. The repository is most likely archived: %s", repoName, ghErr.Message) - } - } - return err -} diff --git a/github/resource_github_repository_vulnerability_alerts_test.go b/github/resource_github_repository_vulnerability_alerts_test.go index 01058b9a88..d4075693d5 100644 --- a/github/resource_github_repository_vulnerability_alerts_test.go +++ b/github/resource_github_repository_vulnerability_alerts_test.go @@ -280,7 +280,7 @@ func TestAccGithubRepositoryVulnerabilityAlerts(t *testing.T) { }, { Config: fmt.Sprintf(repoConfig, repoName, true, alertsBlock), - ExpectError: regexp.MustCompile(`repository is most likely archived`), + ExpectError: regexp.MustCompile(`cannot enable vulnerability alerts on archived repository`), }, }, })