integrations / integrations/terraform-provider-github
[BUG]: security_and_analysis.code_security causes a permanent diff (never read back / never written)
- Dominant language
- Go
- Stars
- 1.2k
- Forks
- 1k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 8
Description
### Expected Behavior
When security_and_analysis.code_security.status is set to "enabled" (and the repository already has Code Security enabled on GitHub), terraform plan should show no changes. The provider should read the code_security status back from the GitHub API into state and send it on create/update, exactly as it already does for secret_scanning and secret_scanning_push_protection.
### Actual Behavior
terraform plan reports a permanent diff on every run, trying to add the code_security block even though the GitHub API already returns code_security.status = "enabled":
```tf
~ resource "github_repository" "this" {
id = ""
~ security_and_analysis {
+ code_security {
+ status = "enabled"
}
# (2 unchanged blocks hidden) # secret_scanning / secret_scanning_push_protection
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
apply does not converge: the next plan shows the same diff again.
## Root cause
The code_security block is declared in the schema, but it is wired into neither the read nor the write path:
- flattenSecurityAndAnalysis() (READ) only sets advanced_security, secret_scanning, secret_scanning_push_protection — it never sets code_security, so the API value (enabled) is dropped and never stored in state.
- calculateSecurityAndAnalysis() (WRITE) only handles those same three fields — it never sends code_security to the API.
Because config always renders code_security {} but state never contains it, Terraform plans to add it forever, and apply never actually writes it.
## Proposed fix
- https://github.com/integrations/terraform-provider-github/blob/f37a4b66a2832ca84af333459352d9dde6a2dbdf/github/resource_github_repository.go#L1190
- https://github.com/integrations/terraform-provider-github/blob/f37a4b66a2832ca84af333459352d9dde6a2dbdf/github/resource_github_repository.go#L553
```
// calculateSecurityAndAnalysis() — WRITE
if ok, status := tryGetSecurityAndAnalysisSettingStatus(lookup, "code_security"); ok {
securityAndAnalysis.CodeSecurity = &github.CodeSecurity{
Status: github.Ptr(status), // on main: new(status)
}
}
// flattenSecurityAndAnalysis() — READ (conditional, like advanced_security)
codeSecurity := securityAndAnalysis.GetCodeSecurity()
if codeSecurity != nil {
securityAndAnalysisMap["code_security"] = []any{map[string]any{
"status": codeSecurity.GetStatus(),
}}
}
```
### Terraform Version
```
Terraform v1.15.2
on linux_amd64
+ provider registry.terraform.io/integrations/github v6.12.1
```
### GitHub Installation Type
- [ ] GitHub.com (Free, Pro, or Team)
- [ ] GitHub Enterprise Server (on-premises)
- [x] GitHub Enterprise Cloud with Personal Accounts (github.com)
- [ ] GitHub Enterprise Cloud with Managed Users/EMU (github.com)
- [ ] GitHub Enterprise Cloud with Data Residency (*.ghe.com)
- [ ] I don't know
### Affected Resource(s)
- github_repository
### Terraform Configuration Files
```hcl
resource "github_repository" "test" {
name = "code-security-repro"
description = "repro for code_security perpetual diff"
visibility = "private"
security_and_analysis {
code_security {
status = "enabled"
}
secret_scanning {
status = "enabled"
}
secret_scanning_push_protection {
status = "enabled"
}
}
}
Precondition: the repository already has Code Security enabled on GitHub (e.g. enabled by an org-level security configuration). Confirm with:
gh api /repos// --jq '.security_and_analysis.code_security'
{"status":"enabled"}
```
### Steps to Reproduce
1. Ensure the repo has code_security enabled on GitHub (verify with the gh api command above → "enabled").
2. Apply the configuration above (apply reports success).
3. Run `terraform plan` again.
=> Plan is NOT empty; it shows `+ code_security { status = "enabled" }`.
4. Run `terraform apply` then `terraform plan` repeatedly.
=> The same diff reappears every time; it never converges.
### Debug Output
```shell
# terraform plan (TF_LOG=DEBUG recommended; relevant excerpt)
~ resource "github_repository" "this" {
id = ""
~ security_and_analysis {
+ code_security {
+ status = "enabled"
}
# (2 unchanged blocks hidden)
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
# Evidence the API already has it enabled (so this is a provider read/write gap, not API state):
$ gh api /repos// --jq '.security_and_analysis'
{
"code_security": { "status": "enabled" },
"secret_scanning": { "status": "enabled" },
"secret_scanning_push_protection": { "status": "enabled" },
...
}
```
### Code of Conduct
- [x] I agree to follow this project's Code of Conduct
Contributor guide
Research direction
Start in github/resource_github_repository.go at calculateSecurityAndAnalysis() and flattenSecurityAndAnalysis(), the write and read entry points named in the issue. Reproduce with the provided Terraform configuration and gh api check, then verify that code_security is sent to and read from the API and repeated terraform plan runs show no diff.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github, go, terraform
- Domain
- devops, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100