Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
3 changes: 2 additions & 1 deletion github/resource_github_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
188 changes: 188 additions & 0 deletions github/resource_github_repository_vulnerability_alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package github

import (
"context"
"net/http"
"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"
)

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": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "The repository name to configure vulnerability alerts for.",
},
"repository_id": {
Type: schema.TypeInt,
Computed: true,
Description: "The ID 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,
Default: true,
Description: "Whether vulnerability alerts are enabled for the repository.",
},
},

CustomizeDiff: diffRepository,
}
}

func resourceGithubRepositoryVulnerabilityAlertsCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
tflog.Info(ctx, "Creating repository vulnerability alerts", map[string]any{"id": d.Id()})
meta := m.(*Owner)
client := meta.v3client

owner := meta.name // TODO: Add owner support // d.Get("owner").(string)
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 {
_, 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)
}
}

d.SetId(strconv.Itoa(int(repo.GetID())))

if err = d.Set("repository_id", repo.GetID()); err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceGithubRepositoryVulnerabilityAlertsRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
tflog.Info(ctx, "Reading repository vulnerability alerts", map[string]any{"id": d.Id()})
meta := m.(*Owner)
client := meta.v3client

owner := meta.name // TODO: Add owner support // d.Get("owner").(string)
repoName := d.Get("repository").(string)
vulnerabilityAlertsEnabled, resp, err := client.Repositories.GetVulnerabilityAlerts(ctx, owner, repoName)
if err != nil {
if resp.StatusCode == http.StatusNotFound {
d.SetId("")
return diag.Errorf("vulnerability alerts don't exist for repository %s/%s, removing resource from state", owner, repoName)
}
return diag.Errorf("error reading repository vulnerability alerts: %s", err.Error())
}
Comment thread
deiga marked this conversation as resolved.
// If no error, but the response status code is 404, we need to check if the repository is accessible.
if resp.StatusCode == http.StatusNotFound {
repo, _, err := client.Repositories.Get(ctx, owner, repoName)
if err != nil {
return diag.Errorf("repository doesn't exist anymore, please remove the resource from your configuration: %s", err.Error())
}
if repo.GetArchived() {
return diag.Errorf("repository %s/%s is archived, please remove the resource from your configuration", owner, repoName)
}
}
tflog.Debug(ctx, "Setting vulnerability alerts enabled state", map[string]any{"owner": owner, "repo_name": repoName, "vulnerability_alerts_enabled": vulnerabilityAlertsEnabled, "response_status": resp.StatusCode})
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 {
tflog.Info(ctx, "Updating repository vulnerability alerts", map[string]any{"id": d.Id()})
meta := m.(*Owner)
client := meta.v3client

owner := meta.name // TODO: Add owner support // d.Get("owner").(string)
repoName := d.Get("repository").(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 {
tflog.Info(ctx, "Deleting repository vulnerability alerts", map[string]any{"id": d.Id()})
meta := m.(*Owner)
client := meta.v3client

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 {
return diag.FromErr(handleArchivedRepoDelete(err, "repository vulnerability alerts", d.Id(), owner, repoName))
}

return nil
}

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()})
repoName := d.Id()
// 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
}
Comment thread
deiga marked this conversation as resolved.

meta := m.(*Owner)
owner := meta.name
client := meta.v3client

repo, _, err := client.Repositories.Get(ctx, owner, repoName)
if 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
}
Loading
Loading