Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ruleset bypass actors diff issues #1950

Merged
merged 3 commits into from
Jan 19, 2024

Conversation

o-sama
Copy link
Contributor

@o-sama o-sama commented Oct 11, 2023

Resolves #1952 (Partial)


Before the change?

  • When updating a ruleset you can get the following:
# github_repository_ruleset.test2 will be updated in-place
  ~ resource "github_repository_ruleset" "test2" {
        id          = "xxxxx"
        name        = "test-12345"
        # (6 unchanged attributes hidden)

      ~ bypass_actors {
          ~ actor_id    = 5 -> 1
          ~ actor_type  = "RepositoryRole" -> "OrganizationAdmin"
            # (1 unchanged attribute hidden)
        }
      ~ bypass_actors {
          ~ actor_id    = 1 -> 5
          ~ actor_type  = "OrganizationAdmin" -> "RepositoryRole"
            # (1 unchanged attribute hidden)
        }

        # (1 unchanged block hidden)
    }

I've seen this happen when the order in which bypass_actor blocks happen to be defined changes. Whether this is done manually or through an automation (I've noticed this happen with something I'm working on which uses a yaml file for defining things).

A while back I made a small change which tries to fix this by sorting when flattening the block, but that doesn't cover this case (and potentially others) and isn't technically the way to do it.

After the change?

  • Now we have a DiffSuppressFunc defined which checks every bypass actor and makes sure a diff only shows up when something does change. The caveat here is it's done several times because each key is passed to the function once. Personally though I would still take this over having a diff every time TF runs, and logically it doesn't make sense to have many bypass actors on a ruleset, so we shouldn't expect a real impact on performance.

The following is the same change as above:

github_repository_ruleset.test2: Refreshing state... [id=xxxxx]
github_organization_ruleset.test: Refreshing state... [id=xxxxx]

No changes. Your infrastructure matches the configuration.

Pull request checklist

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

Does this introduce a breaking change?

Please see our docs on breaking changes to help!

  • Yes
  • No

@o-sama
Copy link
Contributor Author

o-sama commented Oct 12, 2023

I looked into the inability to remove bypass actors by removing the block(s) and it doesn't seem like something that's fixed through the provider's implementation. Please correct me if my thinking below is wrong.

bypass actors is a list of objects, each is a block in TF, this create a slice of type []*BypassActor. in Go, the zero value of a slice is nil, and so, if we create an empty slice or pass nil we get the same behaviour (we create an empty slice in this case).

go-github uses omitempty when serializing the struct into JSON, and automatically omits the empty slice of bypass actors. I don't have visibility into the GitHub API implementation but It seems like when you send a request without bypass actors as a field, it doesn't actually remove them. If we were to send a request with an empty list it should, however, remove them (I think).

E.g. I looked into the debug logs and this is the ruleset in the request sent from the provider to the API:

{
  "name": "test-123",
  "target": "branch",
  "source_type": "Organization",
  "source": "XXXXXXXXXX",
  "enforcement": "active",
  "conditions": {
   "ref_name": {
    "include": [],
    "exclude": []
   },
   "repository_id": {
    "repository_ids": [
     XXXXXXXXXXX,
     XXXXXXXXXXX
    ]
   }
  },
  "rules": [
   {
    "type": "creation"
   },
   {
    "type": "branch_name_pattern",
    "parameters": {
     "name": "test",
     "negate": false,
     "operator": "starts_with",
     "pattern": "test"
    }
   }
  ]
 }

I will test out my theory and if needed, make a PR to go-github to get this addressed in the next release of the client.

@kfcampbell
Copy link
Member

I will test out my theory and if needed, make a PR to go-github to get this addressed in the next release of the client.

That sounds great, thank you @o-sama! We appreciate all your contributions.

@felixlut
Copy link
Contributor

felixlut commented Oct 22, 2023

I randomly stumbled upon this issue myself last week in jdamata/terraform-provider-sonarqube#211.

I started out with defining the selected_projects attribute as a schema.TypeList. While testing the provider I noticed that terraform plan always tried to alter the ordering of the projects, which is just noise. I tried all kinds of weird logic sorting the lists and whatnot, but those where all quite a bit flaky, and just felt too unintuitive. The way I finally solved it was to use a schema.TypeSet instead. From the Terraform documentation the latter is meant to be used when the order matters, while the former is unordered. This solved the issue because Terraform in the plan stage simply didn't care about the ordering of the underlying data, just that they included the same objects.

I'm not sure what implications there would be in switching to the set now that schema.TypeList is out in the wild already (the internal state representation seems to be different from the docs at the very least), but it might be valuable information to know in the future.

From most of the Terraform providers I've looked into so far (including this one), it seems that schema.TypeSet is highly underused in favor of schema.TypeList, especially for nested attributes. I might be overlooking a reason not to use it, but I think an unordered set usually is a more accurate representation of the underlying data than an ordered list.

@o-sama
Copy link
Contributor Author

o-sama commented Oct 22, 2023

I remember when we worked on this initially I saw TypeList used elsewhere and so I used it for most of the nested schemas.

Similarly I wasn't aware this would be an issue to be honest and so it seems like it would be fine.

In hindsight it'd have been better to use TypeSet, but like you pointed out it has potential implications if we change it, even with a state migration function it can still be a breaking change and so a custom diff function is the less intrusive way of avoiding a diff every time this is run.

I am interested though in why it is underused compared to TypeList, although things should be better as the provider is slowly migrated away from the old sdk.

@felixlut
Copy link
Contributor

Ye I'm in the same camp. I'd never used the set for a nested schema before last week, and I'm confused as to why it's not used more. Maybe I'll find out in a month when I curse myself for using it in the SonarQube provider 😅

@kfcampbell
Copy link
Member

@o-sama where did you land on the go-github PR? What does that mean for this PR? I'd like to check just to make sure this doesn't get forgetten.

@stevehipwell
Copy link
Contributor

What needs to happen before we can get this addressed? We're currently seeing a constant churn on both the github_organization_ruleset & github_repository_ruleset.

@o-sama
Copy link
Contributor Author

o-sama commented Nov 13, 2023

@kfcampbell I was tied up between work and a different feature in go-github and haven't implemented the change I mentioned yet. I've worked on it locally but I just have to add test cases and push my changes for review.

I think the PR as is should fix the diff issue but it wouldn't add the ability to remove bypass actors since as far as I'm aware the client lacks that ability still.

I've been abroad for the last week or so but should have some time to work on that in the next couple of days. My bad on the delay!

@usmonster
Copy link
Contributor

Thanks for your effort on this, @o-sama! Please let me know if there's anything you need help with. 🙏

@o-sama
Copy link
Contributor Author

o-sama commented Jan 19, 2024

@kfcampbell & @nickfloyd Apologies for the delay here, It's been a hectic couple of months for me. I'm going to be creating the PR on go-github in the next couple of hours, but in the meantime is it possible for us to get this out and possibly get a release for it when that's appropriate? I think this will still help a lot of folks out with the perpetual diff they're seeing in their rulesets which costs a lot of time since each ruleset edit is at least 1 second with the write delay to account for rate limits.

I'll have to revisit my notes but IIRC once I get the go-github PR merged and released, it'll simply be a matter of updating the client's version and the issue with removing bypass actors would be fixed, so it'd be more of a general update than a code change specific to rulesets.

@kfcampbell
Copy link
Member

@o-sama Sounds good! When that's merged, we can also clean up the diff suppress functions introduced here.

@kfcampbell kfcampbell merged commit 819abbf into integrations:main Jan 19, 2024
3 checks passed
@o-sama
Copy link
Contributor Author

o-sama commented Jan 19, 2024

@kfcampbell The diff suppress func will likely need to stay since this issue comes from the default diff func comparing the objects as a string one line at a time, so you'd likely always have a diff. I'll try changing that to a set at some point and having a state migration func to handle the change without needing anything on the users' end, how does that sound?

By the way thank you for the release! Always appreciate your timely responses!

@kfcampbell
Copy link
Member

Ahh, thanks for clarifying. That sounds good to me! I'm grateful for your contributions to this project.

avidspartan1 pushed a commit to avidspartan1/terraform-provider-github that referenced this pull request Feb 5, 2024
Co-authored-by: Keegan Campbell <me@kfcampbell.com>
kireque pushed a commit to kireque/home-ops that referenced this pull request Feb 7, 2024
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [github](https://registry.terraform.io/providers/integrations/github)
([source](https://togithub.com/integrations/terraform-provider-github))
| required_provider | minor | `5.44.0` -> `5.45.0` |

---

### Release Notes

<details>
<summary>integrations/terraform-provider-github (github)</summary>

###
[`v5.45.0`](https://togithub.com/integrations/terraform-provider-github/releases/tag/v5.45.0)

[Compare
Source](https://togithub.com/integrations/terraform-provider-github/compare/v5.44.0...v5.45.0)

#### What's Changed

- build(deps): bump golang.org/x/crypto from 0.17.0 to 0.18.0 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[integrations/terraform-provider-github#2098
- build(deps): bump golang.org/x/oauth2 from 0.15.0 to 0.16.0 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[integrations/terraform-provider-github#2097
- docs: Adds description for overwrite_on_create option. by
[@&#8203;Nmishin](https://togithub.com/Nmishin) in
[integrations/terraform-provider-github#2095
- docs: Update branch protection documentation by
[@&#8203;LiamMacP](https://togithub.com/LiamMacP) in
[integrations/terraform-provider-github#2085
- feat: Add `required_workflows` to `github_organization_ruleset` by
[@&#8203;relusc](https://togithub.com/relusc) in
[integrations/terraform-provider-github#2082
- Fix ruleset bypass actors diff issues by
[@&#8203;o-sama](https://togithub.com/o-sama) in
[integrations/terraform-provider-github#1950

#### New Contributors

- [@&#8203;LiamMacP](https://togithub.com/LiamMacP) made their first
contribution in
[integrations/terraform-provider-github#2085

**Full Changelog**:
integrations/terraform-provider-github@v5.44.0...v5.45.0

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://togithub.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy4xNzQuMyIsInVwZGF0ZWRJblZlciI6IjM3LjE3NC4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: kireque-bot[bot] <143391978+kireque-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]: github_organization_ruleset unable to remove bypassers
5 participants