Skip to content

feat: add enterprise network configuration support#3274

Open
austenstone wants to merge 25 commits intointegrations:mainfrom
austenstone:feature/github-enterprise-network-configurations
Open

feat: add enterprise network configuration support#3274
austenstone wants to merge 25 commits intointegrations:mainfrom
austenstone:feature/github-enterprise-network-configurations

Conversation

@austenstone
Copy link
Contributor

@austenstone austenstone commented Mar 15, 2026

Overview

This PR adds enterprise-scoped hosted compute network configuration support for GitHub-hosted private networking.

It introduces a new github_enterprise_network_configuration resource and adds network_configuration_id support to github_enterprise_actions_runner_group so enterprise runner groups can be associated with hosted compute network configurations.

This work is closely related to the organization-scoped implementation in #2895, and follows the same review-driven cleanup patterns to stay aligned with current project conventions.

What this PR adds

  • New resource: github_enterprise_network_configuration
  • Full CRUD support for enterprise network configurations
  • Import support for enterprise network configurations
  • network_configuration_id support in github_enterprise_actions_runner_group
  • Acceptance coverage for enterprise network configuration create/update/import flows
  • Acceptance coverage for enterprise runner group private networking association flows
  • Documentation updates for enterprise network configuration and enterprise runner groups

Notes

  • GitHub-hosted private networking is attached through the runner group via network_configuration_id.
  • The runner group create endpoint does not accept network_configuration_id, so the provider applies the networking association with a follow-up PATCH after creation.
  • This branch was cleaned up to mirror the review feedback already applied on the organization-scoped work in #2895: direct state setting in Create, safer GitHub error response checks, and ConfigStateChecks for the newer acceptance assertions.
  • This PR also includes a small correctness fix in the touched runner group read path: getOrganizationRunnerGroup now only swallows 304 Not Modified instead of treating arbitrary ErrorResponse values as cache hits.
  • Runner group Create now sets Terraform state directly from the create response and only falls back to a follow-up Read when the private networking association requires the extra PATCH.

Validation

  • make testacc
  • make test

@github-actions
Copy link

👋 Hi! Thank you for this contribution! Just to let you know, our GitHub SDK team does a round of issue and PR reviews twice a week, every Monday and Friday! We have a process in place for prioritizing and responding to your input. Because you are a part of this community please feel free to comment, add to, or pick up any issues/PRs that are labeled with Status: Up for grabs. You & others like you are the reason all of this works! So thank you & happy coding! 🚀

@github-actions github-actions bot added the Type: Feature New feature or request label Mar 15, 2026
@deiga
Copy link
Collaborator

deiga commented Mar 15, 2026

Your validation commands would not actually run the tests. You should use make testacc and make test

tag-assistant

This comment was marked as resolved.

@austenstone

This comment was marked as resolved.

Copy link

@tag-assistant tag-assistant left a comment

Choose a reason for hiding this comment

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

Re-review ✅

All previous feedback addressed, plus some nice extras:

Addressed:

  • ✅ Shared runnerGroupNetworking struct + helpers in resource_github_actions_runner_group_networking.go — clean dedup
  • getRunnerGroupNetworking now takes a path string, works for both org and enterprise scopes
  • ✅ Trailing newline fixed on enterprise docs
  • StatusNotModified handling added to getRunnerGroupNetworking — consistent with the rest of the codebase

Bonus improvements (not requested):

  • 🧪 173-line unit test file for all three shared helpers (get, update, setState) — including 304 handling and null payload for removal. Solid.
  • 🔧 normalizeEtag() in util.go to handle weak vs strong ETag drift between create and read paths — nice catch, prevents state churn.
  • 🧪 Unit tests for normalizeEtag covering empty, strong, weak, and whitespace cases.

LGTM. Ship it 🚢

Copy link
Collaborator

@deiga deiga left a comment

Choose a reason for hiding this comment

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

Partial review

"network_configuration_id": networkConfigurationID,
}

req, err := client.NewRequest("PATCH", path, payload)
Copy link
Collaborator

Choose a reason for hiding this comment

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

issue: use only go-github provided functions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I checked go-github v83 locally before changing this — there isn’t a first-class runner-group networking method for this endpoint yet, so this still has to stay as a thin NewRequest/Do shim for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With google/go-github#4099, UpdateOrganizationRunnerGroup now accepts NetworkConfigurationID in the request struct, and GetOrganizationRunnerGroup returns it on the response. So yes — once that merges, this raw call can be replaced with the native go-github UpdateOrganizationRunnerGroup/UpdateEnterpriseRunnerGroup functions and the separate getRunnerGroupNetworking GET becomes unnecessary too.

Copy link
Collaborator

@deiga deiga left a comment

Choose a reason for hiding this comment

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

Partial review

networkConfigurationIDValue := networkConfigurationID.(string)
// The create endpoint does not accept network_configuration_id, so private networking
// must be attached with a follow-up PATCH after the runner group has been created.
if _, err = updateRunnerGroupNetworking(client, ctx, fmt.Sprintf("orgs/%s/actions/runner-groups/%d", orgName, runnerGroup.GetID()), &networkConfigurationIDValue); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Isn't this UpdateOrganizationRunnerGroup what you're looking for?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes — once google/go-github#4099 merges, UpdateOrganizationRunnerGroup will carry NetworkConfigurationID natively and this raw call goes away.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That doesn't make sense. The function already exists

Comment on lines +300 to +304
if runnerGroup != nil {
if err = setGithubActionsRunnerGroupState(d, runnerGroup, runnerGroupEtag, selectedRepositoryIDs); err != nil {
return diag.FromErr(err)
}
} else {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please explain this branching logic? Why aren't we setting the state values to nil if api returned nil?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The nil case happens on a 304 Not Modified — the API returned no body, so runnerGroup is nil but resp is valid. In that case we can't call setGithubActionsRunnerGroupState (it'd nil-pointer on the getter methods), but we still need to update selected_repository_ids and etag since those came from separate API calls that did succeed. The rest of state stays untouched from the previous read, which is correct for a not-modified response.

Copy link
Collaborator

Choose a reason for hiding this comment

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

If the GET returned nil, then we need to exit early, instead of doing conditional setting

networkConfigurationIDValue = &value
}

if _, err := updateRunnerGroupNetworking(client, ctx, fmt.Sprintf("orgs/%s/actions/runner-groups/%d", orgName, runnerGroupID), networkConfigurationIDValue); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about UpdateOrganizationRunnerGroup in go-github?

}

func getRunnerGroupNetworking(client *github.Client, ctx context.Context, path string) (*runnerGroupNetworking, *github.Response, error) {
req, err := client.NewRequest("GET", path, nil)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the functions don't exist in go-github, then you should open a PR in there to add them. We don't accept direct API endpoint interactions

austenstone added a commit to austenstone/go-github that referenced this pull request Mar 16, 2026
…unner group types

Add NetworkConfigurationID and HostedRunnersURL fields to EnterpriseRunnerGroup,
and NetworkConfigurationID to CreateEnterpriseRunnerGroupRequest and
UpdateEnterpriseRunnerGroupRequest to match the GitHub API response schema.

These fields already exist on the organization-scoped RunnerGroup type but were
missing from the enterprise equivalents. The GitHub API returns both fields on
enterprise runner group endpoints (List, Get, Create, Update).

Fixes: integrations/terraform-provider-github#3274
The response is always non-nil on the success path — if the API call
errors we return early, and even the 304 Not Modified path returns
a valid response object. The fallback to the stored ETag was unreachable.
@austenstone
Copy link
Contributor Author

All review feedback addressed except the raw NewRequest/Do calls — those are blocked on google/go-github#4099 which adds NetworkConfigurationID to the runner group structs. Once that merges and we bump the dependency, the helpers file goes away and networking flows through the native UpdateOrganizationRunnerGroup/UpdateEnterpriseRunnerGroup functions.

@austenstone
Copy link
Contributor Author

Friendly bump — any chance this could get a review? Happy to address feedback. Thanks!

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

Labels

Type: Feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants