From ba8947d95bb2878e0088892844fe1babc3098cdf Mon Sep 17 00:00:00 2001 From: Simon Scharf Date: Thu, 13 Aug 2026 13:18:38 +0200 Subject: [PATCH] Cache the GHES instance check across organizations enterprise? queried the meta endpoint on every call, and pending_members calls it once per organization. Whether an instance is GHES cannot vary between orgs on that instance, so this was one request per org for a constant answer. Caches against the address rather than the org signature. Checks for the key rather than using ||= because false is a valid cached answer, and is the answer github.com gives. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d95a67cd-ec62-497a-99fc-cf447ee1d49b --- lib/entitlements/service/github.rb | 13 ++++++++++- spec/unit/entitlements/service/github_spec.rb | 22 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/entitlements/service/github.rb b/lib/entitlements/service/github.rb index 0a977a9..d96794c 100644 --- a/lib/entitlements/service/github.rb +++ b/lib/entitlements/service/github.rb @@ -52,6 +52,7 @@ def initialize(addr: nil, org:, token:, ou:, ignore_not_found: false) # need to be obtained only one time per organization, but might be used multiple times. Entitlements.cache[:github_pending_members] ||= {} Entitlements.cache[:github_org_members] ||= {} + Entitlements.cache[:github_enterprise] ||= {} end # Return the identifier, either the address specified or otherwise "github.com". @@ -97,13 +98,23 @@ def org_members end # Returns true if the github instance is an enterprise server instance + # + # Whether an instance is GHES is a property of the instance and not of any one organization, + # so this is cached against the address rather than the org signature. Without this the meta + # endpoint is queried once per organization, which is a request per org for an answer that + # cannot vary between them. Note this caches false as well as true, so it checks for the key + # rather than using ||=, since github.com correctly answers false here. Contract C::None => C::Bool def enterprise? + instance_signature = addr || "" + cache = Entitlements.cache[:github_enterprise] + return cache[instance_signature] if cache.key?(instance_signature) + meta = Retryable.with_context(:default) do octokit.github_meta end - meta.key? :installed_version + cache[instance_signature] = meta.key?(:installed_version) end # Read the members of an organization who are in a "pending" role. These users should diff --git a/spec/unit/entitlements/service/github_spec.rb b/spec/unit/entitlements/service/github_spec.rb index eea708e..7b17aba 100644 --- a/spec/unit/entitlements/service/github_spec.rb +++ b/spec/unit/entitlements/service/github_spec.rb @@ -70,6 +70,28 @@ }) expect(subject.enterprise?).to eq(true) end + + it "queries the API only once per instance across multiple organizations" do + stub = stub_request(:get, "https://github.fake/api/v3/meta"). + to_return({ + body: JSON.dump({ verifiable_password_authentication: true }), + headers: { + content_type: "application/json; charset=utf-8" + } + }) + + other_org = described_class.new( + addr: "https://github.fake/api/v3", + org: "puppiesinc", + token: "GoPackGo", + ou: "ou=puppiesinc,ou=GitHub,dc=github,dc=fake", + ignore_not_found: false + ) + + expect(subject.enterprise?).to eq(false) + expect(other_org.enterprise?).to eq(false) + expect(stub).to have_been_requested.once + end end describe "#pending_members" do