Skip to content

Add github_repository backend for direct repository access [model slop POC, don't review] - #307

Open
hosom wants to merge 5 commits into
mainfrom
github-repository-backend
Open

hosom wants to merge 5 commits into
mainfrom
github-repository-backend

Conversation

@hosom

@hosom hosom commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a github_repository backend with validated role files and individual-only repository-local grants.
  • Add/update declared direct users; remove undeclared non-owner direct grants (including outside collaborators) and direct organization-team repository associations.
  • Discover live organization membership, default repository permissions, and every organization role and its paginated direct/indirect/mixed user assignments. No role-name allowlist; custom and enterprise-defined organization roles use their metadata.
  • Accept declared owners. Explicitly defer ambiguous owner direct grants and requested roles below inherited organization access instead of rejecting the entire run, inventing higher roles, or reporting false direct-grant convergence.
  • Use repository-team access_source to preserve organization/enterprise access. Only direct organization-team associations are deleted. Unknown/missing metadata fails closed; enterprise-team associations remain explicit unmanaged policy exceptions.
  • Preserve organization roles, team membership/hierarchy, repository visibility and access to other repositories. Apply user upserts before cleanup, reject stale repository/organization snapshots, and verify the deferral-aware resulting state.

Validation

  • All 316 unit examples pass with 100% line coverage; full RuboCop passes.
  • Mocked reconciliation, pagination, all feature combinations, all five organization repository base roles, arbitrary/custom roles, team-derived role assignments, owner/JIT transitions, source-aware team cleanup, incomplete metadata, stale plans, and residual grants are covered.

Required read permissions / live gate

Organization Administration: read and Custom organization roles: read are now required, alongside Members: read and repository permissions. The App must expose organization base settings, the full role catalog/assignments, collaborator permissionSources, and repository-team access_source. Missing permissions or unsupported APIs fail closed.

The prior successful read-only demo in github/entitlements#142229 used preview 1.2.6.pre.repository.g224de61218a0 and confirmed three direct team-removal calculations. It does not validate the generalized organization-role reader added in c522a17. The refreshed preview 1.2.6.pre.repository.gc522a17097b2 is now pushed to github/entitlements#142229 at commit 285d75533ecc7bce9754f3c01e4fe41a87cd177b. Its CI job installed the preview but failed preflight because the App installation lacks organization_administration and organization_custom_org_roles read permissions. App/installation approval and a successful rerun are required before this live gate is satisfied. No live mutations or production convergence tests have been performed.

Deferrals are visible exceptions, not full convergence to role files. Existing higher direct grants can remain while deferred. JIT expiry is handled on a later calculation, not atomically with privilege changes.

Tracking: github/sae-iam-team#3141.

This PR does not include the unrelated team GraphQL batching changes in #301.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b
Copilot AI balanced review requested due to automatic review settings September 24, 2026 20:47
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Membership snapshots, incomplete permission sources, and pending invitations currently undermine fail-closed reconciliation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity · 1 Medium severity

Open (3)
What changed in this PR

Adds a backend for managing direct, role-aware GitHub repository access.

Changes:

  • Loads validated repository role files.
  • Reconciles direct grants through GraphQL and REST.
  • Adds comprehensive tests and rollout documentation.
File Description
README.md Documents configuration and rollout.
lib/​entitlements/​backend/​github_repository.rb Defines and loads the backend.
lib/​entitlements/​backend/​github_repository/​configuration.rb Validates and loads role files.
lib/​entitlements/​backend/​github_repository/​controller.rb Coordinates reconciliation.
lib/​entitlements/​backend/​github_repository/​models/​repository_access.rb Models role-aware access.
lib/​entitlements/​backend/​github_repository/​provider.rb Calculates repository changes.
lib/​entitlements/​backend/​github_repository/​service.rb Implements GitHub reads and mutations.
spec/​unit/​entitlements/​backend/​github_repository_spec.rb Tests backend behavior.
spec/​unit/​spec_helper.rb Loads the backend in tests.
spec/​unit/​fixtures/​repositories/​other.repo/​maintain.txt Adds group-rule fixture.
spec/​unit/​fixtures/​repositories/​other.repo/​admin.yaml Adds expired-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​write.rb Adds Ruby-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​triage.yaml Adds YAML-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​read.txt Adds text-rule fixture.

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

Comment on lines +40 to +42
def apply(repository, instructions)
Configuration.validate_repository!(repository)
instructions.sort_by { |instruction| [instruction.fetch(:action) == :upsert ? 0 : 1, instruction.fetch(:login).downcase] }.each do |instruction|
Comment on lines +132 to +137
if status == 201
unless result.is_a?(Sawyer::Resource) && result[:id].is_a?(Integer) && result[:id] > 0
GitHubRepository.fail!("Malformed repository invitation response")
end
Entitlements.logger.warn("#{repository}: invitation created for #{instruction.fetch(:login)}; access is not yet active")
end
Comment on lines +86 to +88
unless edge.is_a?(Hash) && edge["node"].is_a?(Hash) && edge["permissionSources"].is_a?(Array)
GitHubRepository.fail!("Missing or malformed repository permission sources")
end
@hosom hosom changed the title Add github_repository backend for direct repository access Add github_repository backend for direct repository access [model slop POC, don't review] Sep 24, 2026
@hosom

hosom commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

The vendored-gem demo is available in github/entitlements#142229 (draft, DO NOT MERGE). It pins preview version 1.2.6.pre.repository.gc8c3584339bf from commit c8c3584339bf, adds github/entitlements-app role data, and exercises actual configuration → packaged backend → paginated GraphQL/REST simulation → no-op convergence. The full entitlements suite passes locally (223 examples, 0 failures, 8 existing pending). Live reads remain blocked by the available OAuth token lacking admin:org for permissionSources/roleName; no live mutations were made.

The live entitlements-default demo proved edge.permission adds a public_repo scope requirement to an admin:org token. Read only the source-specific roles consumed by reconciliation, without broadening credentials or falling back to effective permissions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b
@hosom

hosom commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

The real github/entitlements#142229 no-op calculation exposed an unnecessary credential requirement in the initial query: effective edge.permission requires public_repo, while CI has admin:org. Commit d12e39a removes that unused field, retaining exact direct permissionSources.roleName and strict error handling. No token scopes were broadened. A regression test guards the requested fields; all 285 plugin examples pass with 100% line coverage. The demo now vendors the refreshed source-commit-derived gem and is rerunning the actual entitlements-default calculation. No live mutations or merge are involved.

Remove all repository team associations and undeclared direct grants, including outside collaborators. Preserve team hierarchy and membership, order user upserts before cleanup, and verify snapshots before and after application.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a8107bce-2500-45f8-b046-3f50092d9fbd
@hosom

hosom commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Published individual-only repository reconciliation in 224de61218a0721768b5c37c338f8a25aa88198c and rebuilt the preview for github/entitlements#142229.

The live read-only App no-op run succeeded and now proposes removal of github/sae-iam, github/sae-iam-reviewers, and github/sae-reviewers from entitlements-app: https://github.com/github/entitlements/actions/runs/36142358100/job/108095019791. No live mutations were made.

Production gate discovered: the declared user currently has organization-owner JIT access and the backend rejects desired owners. The demo uses the existing warn-and-skip setting to verify team cleanup, not as a production fix. Owner declarations/direct-grant persistence during JIT elevation need an explicit policy and API validation before rollout. This live run does not verify owner grant creation or applied convergence.

Discover base permissions and every organization role and assignment. Accept owners as desired users, defer ambiguous owner grants and roles below inherited access, and preserve organization/enterprise team sources using access_source. Refresh organization access for stale-plan and convergence checks, fail closed on incomplete metadata, and document required read permissions and policy exceptions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a8107bce-2500-45f8-b046-3f50092d9fbd
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.

2 participants