Skip to content

feat(organization_ruleset): support the repository target - #3598

Open
yordis wants to merge 4 commits into
integrations:mainfrom
yordis:yordis/feat-org-ruleset-repository-target
Open

feat(organization_ruleset): support the repository target#3598
yordis wants to merge 4 commits into
integrations:mainfrom
yordis:yordis/feat-org-ruleset-repository-target

Conversation

@yordis

@yordis yordis commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Resolves #2777


Before the change?

After the change?

  • github_organization_ruleset accepts target = "repository", so repository creation, deletion, naming, transfer and visibility policies are declarable and importable like every other ruleset.
  • Five rules are added for that target: repository_create, repository_delete, repository_transfer, repository_name (pattern, negate) and repository_visibility.
  • Rules and conditions are validated per target at plan time rather than failing at the API, and target is now checked against the four values the API documents instead of accepting any string.

Testing

Verified end to end against a live organization using a local build of this branch via dev_overrides. Create, read, update and delete all exercised against the API.

Create. A ruleset using all five rules, applied clean, and the server stored exactly the intended payload:

"rules": [
  {"type": "repository_create"},
  {"type": "repository_delete"},
  {"type": "repository_name", "parameters": {"negate": false, "pattern": "^tmp-writepath-"}},
  {"type": "repository_transfer"},
  {"type": "repository_visibility", "parameters": {"internal": true, "private": true, "public": false}}
]

This confirms the parameter shapes: repository_create/repository_delete/repository_transfer marshal as bare rules with no parameters, and repository_name as {negate, pattern}. A follow-up plan was empty, so all five round-trip through read.

Update. Removing a bare rule, flipping negate, changing pattern and flipping internal applied as a single in-place change, the server reflected each one, and the follow-up plan was empty.

Import. An existing repository-target ruleset created through the UI imported cleanly, both directly and through an import block (1 to import, 0 to add, 0 to change, 0 to destroy), with an empty plan afterwards.

Delete. Destroy removed it; the API returns 404.

Validation, rejected at plan time:

Config Error
repository target with ref_name ref_name must not be set for repository target
repository target with creation rule "creation" is not valid for repository target; repository targets only support: [...]
branch target with repository_delete rule "repository_delete" is not valid for branch target; ...
target = "bogus" expected target to be one of ["branch" "tag" "push" "repository"], got bogus

Unit tests, gofmt, go vet and golangci-lint are clean. New unit coverage: round-trip expand/flatten for all five rules, a check that the rules are omitted for github_repository_ruleset (whose schema lacks them), a pairwise-disjointness test across the three target rule lists, and conditions validation for the new target. Acceptance tests are included but I cannot run the mutating suite in CI myself.

Known gap: public visibility, needs a go-github change

go-github's RepositoryVisibilityRuleParameters has only Internal and Private, in v89 and on master, while the API returns and accepts public. I confirmed the consequence on a throwaway ruleset rather than assuming it:

  1. Set public: true out of band via the REST API.
  2. tofu plan reported no changes. The provider cannot see the drift.
  3. Applied an unrelated change (the repository_name pattern only).
  4. public came back false. The value was silently discarded.

So a repository ruleset that permits public repos would have that quietly revoked by any unrelated apply. That is a data-loss path, and it is not fixable in this provider alone: the field has to exist in go-github first. I am happy to open that change and rebase this PR on it if maintainers agree that is the right order. Everything else here is unaffected, since the other four rules and the internal/private parameters round-trip correctly.

Pull request checklist

  • Schema migrations have been created if needed (example)
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes / features)

The new rules are optional attributes on an existing resource, so no state migration is needed.

Does this introduce a breaking change?

Please see our docs on breaking changes to help!

  • Yes
  • No

Existing branch, tag and push configurations are untouched. The one behaviour change to call out is that target is now validated against those four values at plan time, where it previously accepted any string and failed at the API instead.


I used an AI assistant while writing this. I have read every line, verified the API behaviour against the REST docs and against live calls rather than taking the model's word for it, and ran the resources end to end against a real organization before opening this, as tabulated above.

@deiga

deiga commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Please show a screenshot of an Org level ruleset with repository target. AFAIK the docs lie and the repository target is only available on Enterprise level

@yordis

yordis commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

@deiga unless I do not understand my own GitHub org, my apologies if I did a mistake here, I honestly thought this is the normal flow

Screen.Recording.2026-08-07.at.2.55.18.PM.mov

@deiga

deiga commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

@yordis you have understood totally fine. I wasn't aware that it's under a different UI menu! 🙏

@deiga deiga added Status: Triage This is being looked at and prioritized r/organization_ruleset Type: Feature New feature or request labels Aug 7, 2026

@deiga deiga left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice changes! Would you be open for improving the docs bit?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: would you have the courage to refactor this template to use the auto-generated schema instead of manually doing the schema changes?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Please split examples into multiple files and move them to examples/resources/github_organization_ruleset/resource_<name|number>.tf

@yordis
yordis requested a review from deiga August 10, 2026 02:48
@yordis

yordis commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@deiga check again and let me know 🙏🏻

@deiga
deiga requested a balanced review from Copilot August 10, 2026 04:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

These provider review instructions are being used.

Adds repository-target organization rulesets, including target-specific validation, rules, tests, examples, and generated documentation.

Changes:

  • Adds five repository-target rules and serialization support.
  • Adds target-aware validation and tests.
  • Updates examples, imports, templates, and generated docs.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
github/resource_github_organization_ruleset.go Adds repository target schema.
github/resource_github_organization_ruleset_test.go Adds acceptance and validation tests.
github/util_rules.go Expands and flattens repository rules.
github/util_rules_test.go Tests rule round-tripping.
github/util_ruleset_validation.go Adds target-specific validation.
github/util_ruleset_validation_test.go Tests validation and rule separation.
examples/resources/github_organization_ruleset/resource_1.tf Retains the primary example.
examples/resources/github_organization_ruleset/resource_2.tf Extracts the push example.
examples/resources/github_organization_ruleset/resource_3.tf Adds a repository-target example.
examples/resources/github_organization_ruleset/import.sh Documents CLI import.
examples/resources/github_organization_ruleset/import-by-string-id.tf Documents import blocks.
templates/resources/organization_ruleset.md.tmpl Modernizes generated documentation.
docs/resources/organization_ruleset.md Publishes updated schema and examples.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread github/util_rules.go
Comment on lines +682 to +685
rulesetRules.RepositoryVisibility = &github.RepositoryVisibilityRuleParameters{
Internal: repositoryVisibilityMap["internal"].(bool),
Private: repositoryVisibilityMap["private"].(bool),
}
Comment thread github/resource_github_organization_ruleset_test.go
Comment thread github/resource_github_organization_ruleset_test.go Outdated
@yordis

yordis commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

@deiga should I address Copilot until it is happy with things?

yordis added 4 commits August 17, 2026 00:38
GitHub organization rulesets accept a `repository` target that governs
repository creation, deletion, naming, transfer and visibility, but the
provider rejected it, leaving those org policies unmanageable in
Terraform and silently destructive on import.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…urce schema

Hand-maintained argument and attribute tables drift from the schema they
describe, so the docs already disagreed with the resource on the push and
repository targets.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…yout

The page hardcoded prose the provider can supply itself and described
importing in text the tooling can no longer verify against the resource.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
…ead from the ID alone

Import is the path where the old provider silently rewrote the ruleset as a branch ruleset, so the new target needs coverage that does not lean on config-seeded state.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis

yordis commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Heads up on a related gap I hit while working on this, and filed upstream as google/go-github#4455.

The repository_visibility rule has a third toggle, public, alongside internal and private. RepositoryVisibilityRuleParameters in go-github does not model it, so encoding/json drops it on decode. Because updating a ruleset is a full replace, a read-modify-write through the SDK omits the key and the API resolves it back to false.

I verified this against a live target: repository ruleset: the server sends {"public":false,"internal":true,"private":true}, the SDK decodes it as {"internal":true,"private":true}, and setting public through the typed API is not expressible at all today.

That means this PR ships repository_visibility with two of the three toggles, and Terraform managing such a ruleset will reset public to false. Nothing to change here, since the field cannot be plumbed through until the SDK supports it. Once #4455 lands and is released, the follow-up is a dependency bump plus a public attribute on the repository_visibility block.

Filing this so the limitation is on the record rather than discovered later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r/organization_ruleset Status: Triage This is being looked at and prioritized Type: Feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT]: Add repository target to github_organization_ruleset

3 participants