integrations / integrations/terraform-provider-github

[BUG]: security_and_analysis.code_security causes a permanent diff (never read back / never written)

Open Beginner friendly
#3,501 1 comment 0 reactions 0 assignees View on GitHub
r/repository Type: Bug vNext
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.