Skip to content
Open
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
3 changes: 3 additions & 0 deletions examples/repository_security_and_analysis/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ resource "github_repository" "terraformed" {
secret_scanning_push_protection {
status = "enabled"
}
private_vulnerability_reporting {
status = "enabled"
}
}
}

97 changes: 96 additions & 1 deletion github/resource_github_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ func resourceGithubRepository() *schema.Resource {
},
},
},
"private_vulnerability_reporting": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Description: "The private vulnerability reporting configuration for the repository.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"status": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"enabled", "disabled"}, false), "private_vulnerability_reporting"),
Description: "Set to 'enabled' to enable private vulnerability reporting on the repository. Can be 'enabled' or 'disabled'.",
},
},
},
},
},
},
},
Expand Down Expand Up @@ -568,6 +586,9 @@ func calculateSecurityAndAnalysis(d *schema.ResourceData) *github.SecurityAndAna
Status: github.String(status),
}
}
// Note: private_vulnerability_reporting is handled separately via the
// EnablePrivateReporting/DisablePrivateReporting API, not via the
// repository Edit API's SecurityAndAnalysis field.

return &securityAndAnalysis
}
Expand Down Expand Up @@ -773,6 +794,11 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta any) error {
return err
}

err = updatePrivateVulnerabilityReporting(d, client, ctx, owner, repoName)
if err != nil {
return err
}

return resourceGithubRepositoryUpdate(d, meta)
}

Expand Down Expand Up @@ -900,7 +926,38 @@ func resourceGithubRepositoryRead(d *schema.ResourceData, meta any) error {
}
}

if err = d.Set("security_and_analysis", flattenSecurityAndAnalysis(repo.GetSecurityAndAnalysis())); err != nil {
securityAndAnalysis := flattenSecurityAndAnalysis(repo.GetSecurityAndAnalysis())

// Private Vulnerability Reporting is not returned in the SecurityAndAnalysis
// from the repository API. We need to fetch it separately.
pvrEnabled, resp, err := client.Repositories.IsPrivateReportingEnabled(ctx, owner, repoName)
if err != nil {
// PVR is only available for public repos. A 404 means it's not available (e.g., private repo).
// Any other error should be returned.
if resp == nil || resp.StatusCode != http.StatusNotFound {
return fmt.Errorf("error reading private vulnerability reporting status: %w", err)
}
log.Printf("[DEBUG] Private vulnerability reporting not available for repository %s/%s", owner, repoName)
} else {
// Merge the PVR status into the security_and_analysis map
status := "disabled"
if pvrEnabled {
status = "enabled"
}
// Initialize securityAndAnalysis if it's empty (can happen for private repos)
if len(securityAndAnalysis) == 0 {
securityAndAnalysis = []any{make(map[string]any)}
}
saMap, ok := securityAndAnalysis[0].(map[string]any)
if !ok {
return fmt.Errorf("failed to parse security_and_analysis map")
}
saMap["private_vulnerability_reporting"] = []any{map[string]any{
"status": status,
}}
}

if err = d.Set("security_and_analysis", securityAndAnalysis); err != nil {
return err
}

Expand Down Expand Up @@ -1007,6 +1064,13 @@ func resourceGithubRepositoryUpdate(d *schema.ResourceData, meta any) error {
}
}

if d.HasChange("security_and_analysis") {
err = updatePrivateVulnerabilityReporting(d, client, ctx, owner, repoName)
if err != nil {
return err
}
}

if d.HasChange("visibility") {
o, n := d.GetChange("visibility")
repoReq.Visibility = github.String(n.(string))
Expand Down Expand Up @@ -1218,6 +1282,9 @@ func flattenSecurityAndAnalysis(securityAndAnalysis *github.SecurityAndAnalysis)
"status": securityAndAnalysis.GetSecretScanningPushProtection().GetStatus(),
}}

// Note: private_vulnerability_reporting is not returned by the repository API
// and is fetched separately via IsPrivateReportingEnabled in the Read function.

return []any{securityAndAnalysisMap}
}

Expand Down Expand Up @@ -1251,3 +1318,31 @@ func updateVulnerabilityAlerts(d *schema.ResourceData, client *github.Client, ct
_, err := updateVulnerabilityAlerts(ctx, owner, repoName)
return err
}

func updatePrivateVulnerabilityReporting(d *schema.ResourceData, client *github.Client, ctx context.Context, owner, repoName string) error {
value, ok := d.GetOk("security_and_analysis")
if !ok {
return nil
}

asList := value.([]any)
if len(asList) == 0 || asList[0] == nil {
return nil
}

lookup := asList[0].(map[string]any)
if pvr, ok := lookup["private_vulnerability_reporting"].([]any); ok && len(pvr) > 0 && pvr[0] != nil {
pvrMap := pvr[0].(map[string]any)
if status, ok := pvrMap["status"].(string); ok {
if status == "enabled" {
_, err := client.Repositories.EnablePrivateReporting(ctx, owner, repoName)
return err
} else if status == "disabled" {
_, err := client.Repositories.DisablePrivateReporting(ctx, owner, repoName)
return err
}
}
}

return nil
}
61 changes: 61 additions & 0 deletions github/resource_github_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,67 @@ func TestAccGithubRepositorySecurity(t *testing.T) {
})
})
})

t.Run("manages private vulnerability reporting for a public repository", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-%s"
description = "A repository created by Terraform to test private vulnerability reporting"
visibility = "public"
security_and_analysis {
secret_scanning {
status = "enabled"
}
secret_scanning_push_protection {
status = "disabled"
}
private_vulnerability_reporting {
status = "enabled"
}
}
}
`, randomID)

check := resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"github_repository.test", "security_and_analysis.0.secret_scanning.0.status",
"enabled",
),
resource.TestCheckResourceAttr(
"github_repository.test", "security_and_analysis.0.secret_scanning_push_protection.0.status",
"disabled",
),
resource.TestCheckResourceAttr(
"github_repository.test", "security_and_analysis.0.private_vulnerability_reporting.0.status",
"enabled",
),
)
testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
testCase(t, individual)
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}

func TestAccGithubRepositoryVisibility(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions website/docs/r/repository.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ The `security_and_analysis` block supports the following:

* `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.

* `private_vulnerability_reporting` - (Optional) The private vulnerability reporting configuration for the repository. See [Private Vulnerability Reporting Configuration](#private-vulnerability-reporting-configuration) below for details.

#### Advanced Security Configuration ####

The `advanced_security` block supports the following:
Expand All @@ -204,6 +206,10 @@ The `advanced_security` block supports the following:

* `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.

#### Private Vulnerability Reporting Configuration ####

* `status` - (Optional) Set to `enabled` to enable private vulnerability reporting on the repository. Can be `enabled` or `disabled`. This feature allows security researchers to privately report potential security vulnerabilities to repository maintainers. See [GitHub Security Advisories](https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/about-repository-security-advisories) for more details. Only available for public repositories.

### Template Repositories

`template` supports the following arguments:
Expand Down