Manage GitHub org settings and org-role assignments via Pulumi (#107)
* Manage GitHub org settings and org-role assignments via Pulumi Brings two click-ops org-level configs under IaC and tightens defaults: - OrganizationSettings: default_repository_permission read -> none so private repos are not implicitly readable by every member; repo creation restricted to admins; billingEmail from Pulumi secret; security new-repo defaults pinned so the provider does not reset them. - Org-role assignments: codify lead/core-maintainers -> all_repo_admin. moderators -> all_repo_triage and anthropic -> all_repo_write are intentionally omitted (being removed). * Fix config namespace: use project namespace for githubBillingEmail The github: namespace is reserved for the @pulumi/github provider's own config keys, so github:billingEmail was rejected as an unknown provider option. Use the project default namespace instead. preview.yml uses the same --config flag pattern as the existing Discord secrets.
This commit is contained in:
parent
945668a063
commit
65b5a43451
1 changed files with 98 additions and 0 deletions
|
|
@ -1,10 +1,26 @@
|
|||
import * as pulumi from '@pulumi/pulumi';
|
||||
import * as github from '@pulumi/github';
|
||||
import { ROLES, type Role, buildRoleLookup } from './config/roles';
|
||||
import { REPOSITORY_ACCESS } from './config/repoAccess';
|
||||
import { ORG_ROLE_ASSIGNMENTS } from './config/orgRoles';
|
||||
import { ORG_SETTINGS } from './config/orgSettings';
|
||||
import { MEMBERS } from './config/users';
|
||||
import { sortRolesByGitHubDependency } from './config/utils';
|
||||
import type { RoleId } from './config/roleIds';
|
||||
|
||||
const config = new pulumi.Config();
|
||||
|
||||
// The provider's Create for this resource is a PATCH on the existing org, so
|
||||
// no import is needed; first apply writes the values below directly.
|
||||
new github.OrganizationSettings(
|
||||
'org-settings',
|
||||
{
|
||||
...ORG_SETTINGS,
|
||||
billingEmail: config.requireSecret('githubBillingEmail'),
|
||||
},
|
||||
{ additionalSecretOutputs: ['billingEmail'] }
|
||||
);
|
||||
|
||||
const roleLookup = buildRoleLookup();
|
||||
// Teams keyed by GitHub team name (matches repoAccess.ts references)
|
||||
const teams: Record<string, github.Team> = {};
|
||||
|
|
@ -50,6 +66,26 @@ MEMBERS.forEach((member) => {
|
|||
});
|
||||
});
|
||||
|
||||
// Assign organization-level roles to teams (grants access across all repos)
|
||||
const orgRoles = github.getOrganizationRolesOutput();
|
||||
ORG_ROLE_ASSIGNMENTS.forEach((assignment) => {
|
||||
const team = teams[assignment.team];
|
||||
if (!team) {
|
||||
throw new Error(
|
||||
`orgRoles.ts references team '${assignment.team}' which is not managed in roles.ts`
|
||||
);
|
||||
}
|
||||
const roleId = orgRoles.roles.apply((roles) => {
|
||||
const match = roles.find((r) => r.name === assignment.role);
|
||||
if (!match) throw new Error(`Organization role '${assignment.role}' not found`);
|
||||
return match.roleId;
|
||||
});
|
||||
new github.OrganizationRoleTeam(`orgrole-${assignment.team}-${assignment.role}`, {
|
||||
teamSlug: team.slug,
|
||||
roleId,
|
||||
});
|
||||
});
|
||||
|
||||
// Configure repository access
|
||||
REPOSITORY_ACCESS.forEach((repo) => {
|
||||
new github.RepositoryCollaborators(`repo-${repo.repository}`, {
|
||||
|
|
|
|||
Loading…
Reference in a new issue