diff --git a/openspec/changes/restrict-private-repo-access/.openspec.yaml b/openspec/changes/restrict-private-repo-access/.openspec.yaml new file mode 100644 index 0000000..5e6d53a --- /dev/null +++ b/openspec/changes/restrict-private-repo-access/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-07-24 diff --git a/openspec/changes/restrict-private-repo-access/design.md b/openspec/changes/restrict-private-repo-access/design.md new file mode 100644 index 0000000..4b52977 --- /dev/null +++ b/openspec/changes/restrict-private-repo-access/design.md @@ -0,0 +1,165 @@ +## Context + +The complytime GitHub organization manages its structure (members, teams, repos, permissions) as code through `peribolos.yaml` in the public `.github` repository. Peribolos reconciles this config against GitHub on every push to main and on a daily schedule. + +Currently, `default_repository_permission` is set to `read`, granting all 32 org members implicit read access to every repository, including private ones (nunya, roadmap). Private repo access is supplemented by a manually-managed secret team (`nunya-access`) that was created to survive peribolos reconciliation (commit `d603ac5`, May 29, 2026). The `--ignore-secret-teams` flag was added to both `peribolos-apply.yml` and `peribolos-drift.yml` to prevent peribolos from deleting this team. + +The organization plans to onboard external open-source contributors. Under the current default, any new org member would immediately gain read access to all private repositories containing sensitive information. + +### Current member landscape + +- 4 admins (always have full access regardless of settings) +- 9 members in teams with explicit repo access (engineers) +- 19 members with zero team membership (managers, stakeholders) who rely entirely on the org-wide `read` default + +### Constraints + +- `peribolos.yaml` lives in the public `.github` repository -- its contents are visible to anyone +- Peribolos runs with `--fix-org`, `--fix-teams`, `--fix-team-members`, `--fix-repos`, `--fix-team-repos` -- it reconciles all aspects of org state +- GitHub's base permission is a floor: team grants override it upward, never downward + +## Goals / Non-Goals + +**Goals:** + +- Prevent future external org members from accessing private repositories +- Codify private repository access in `peribolos.yaml` so changes are PR-reviewed and drift-detected +- Maintain uninterrupted access for current members during the migration +- Document what org-structure information becomes publicly visible and what remains private + +**Non-Goals:** + +- Auditing which of the 19 teamless members actually need private repo access (deferred to a follow-up) +- Changing team structure for public repos (engineers' access is already correct) +- Managing access for repos outside the complytime org + +## Decisions + +### Decision 1: Change `default_repository_permission` to `none` + +**Choice**: Set the org-wide base permission to `none`. + +**Alternatives considered**: +- Keep `read` and manage access per-repo via collaborators: Does not scale; no code review, no drift detection, requires per-repo manual management. +- Set to `read` and use repo-level overrides: GitHub does not support lowering access below the org default on a per-repo basis. The base permission is a floor, not a ceiling. + +**Rationale**: `none` is the only value that prevents org members from implicitly accessing private repos. For public repos, the change is transparent -- public repos are visible to anyone on the internet regardless of base permission. Engineers already have explicit team-based access to all repos they work on. + +### Decision 2: Bring private repos into peribolos-managed config + +**Choice**: Add nunya and roadmap to the `repos` section of `peribolos.yaml` and create closed teams for access. + +**Alternatives considered**: +- Keep using manually-managed secret teams: Works for 1-2 repos but does not scale. No PR review on access changes, no drift detection, no git audit trail. Requires the `--ignore-secret-teams` workaround. +- Use direct collaborators (per-user, per-repo): Even less scalable; no team abstraction, no code review. + +**Rationale**: Codifying access in `peribolos.yaml` provides the same governance model used for all other org resources: changes go through PR review, peribolos detects drift, and git history records who changed what and when. + +### Decision 3: Use role-based teams spanning all private repos + +**Choice**: Create teams organized by access pattern (role), not by repo. + +Structure: +- `private-repos-readers`: read access to all private repos (managers, stakeholders) +- `private-repos-writers`: write access to all private repos (contributing engineers) +- `private-repos-maintainers`: maintain access to all private repos (project leads) + +A single team can grant different permission levels per repo in its `repos` map, but all members of a team get the same permissions. Using the "highest wins" principle, a member in both `private-repos-readers` and `private-repos-writers` gets write access. + +**Alternatives considered**: +- One team per repo-permission combination (nunya-read, nunya-write, roadmap-read, etc.): Combinatorial explosion -- 2 repos x 3 levels = 6 teams; scales to N x M. +- One team per repo: Still requires multiple teams per repo if different members need different permission levels. + +**Rationale**: In practice, access patterns tend to be role-based (observers read everything, engineers write to everything they work on). This keeps the team count at O(permission-levels) rather than O(repos x permission-levels). If a specific member needs an asymmetric pattern (e.g., write on nunya but read on roadmap), they can be placed in `private-repos-readers` and a separate team can grant write on nunya only. + +### Decision 4: Sequencing -- teams first, then default change + +**Choice**: Apply changes in two phases to avoid any access gap. + +Phase 1: Add private repo entries and teams to `peribolos.yaml`, merge and let peribolos create the teams. +Phase 2: Change `default_repository_permission` to `none` in a separate PR. + +**Rationale**: If the default is changed before teams exist, all 19 teamless members immediately lose access to private repos. Creating teams first ensures access is in place before the floor is removed. + +### Decision 5: Remove `--ignore-secret-teams` after migration + +**Choice**: Remove the flag from both `peribolos-apply.yml` and `peribolos-drift.yml` after the `nunya-access` secret team is manually deleted from GitHub. + +**Rationale**: The flag was a workaround for managing a secret team outside of peribolos. Once all access is codified in closed teams, the flag is no longer needed. Removing it restores full reconciliation coverage -- peribolos will detect and flag any manually-created teams, which is the desired behavior. + +## Risks / Trade-offs + +### Threat model: information exposure in the public config + +Adding private repos to `peribolos.yaml` (which lives in the public `.github` repository) exposes organizational metadata. This section analyzes the threat model for each category of exposed information. + +#### What is exposed vs. what remains private + +| Information | Currently visible? | After this change | Risk level | +|---|---|---|---| +| Private repo names (nunya, roadmap) | No | Yes | Low (opaque names reveal nothing about content) | +| Private repo descriptions | No | Yes (if set) | **Variable** (depends entirely on description text) | +| That these repos are private | No | Yes (`private: true`) | Minimal (confirms existence, attacker still can't access) | +| Who has access to private repos | No | Yes (team memberships) | Low-Medium (see social engineering analysis below) | +| What permission level each person has | No | Yes (team repos mapping) | Low (read vs. write is minor signal) | +| Repo contents (code, issues, PRs) | No | **Still no** | N/A (content protection is strengthened) | +| Git history of access changes | No | Yes (PR history) | Low (audit trail is a feature, not a risk) | + +#### Threat: repo descriptions leak sensitive context + +The `description` field is the primary vector for accidental information leakage. Repo names like "nunya" and "roadmap" are opaque, but a description like "Security vulnerability tracking and incident response playbooks" would reveal the repo's purpose to anyone browsing the public config. + +**Mitigation**: Repo descriptions in `peribolos.yaml` SHALL be omitted or set to generic, non-revealing text (e.g., "Internal project repository"). The spec includes a formal requirement for this. + +#### Threat: repo names leak strategic intent + +Current repo names (nunya, roadmap) are innocuous. However, future private repos with names like "cve-2026-xxxx-response" or "acquisition-target-analysis" would leak strategic information through the name alone. + +**Mitigation**: Private repository names SHALL be opaque or generic. The spec includes a naming convention requirement to prevent information leakage through repo names. + +#### Threat: team membership enables social engineering + +Exposing which specific users have access to private repos could help an attacker target phishing or account compromise attempts at those individuals. + +**Analysis**: This risk is **incremental, not new**. The full org membership list (all 32 usernames) is already public in `peribolos.yaml`. An attacker already knows every org member. The new information is which subset has private repo access specifically. Since all 32 members currently have implicit read access to private repos via `default_repository_permission: read`, the current targeting surface is actually larger (any org member is a valid target). After this change, only team members are valid targets -- a smaller, more controlled set. + +**Mitigation**: No additional mitigation needed beyond existing GitHub account security practices (2FA, SSO). + +#### Net security posture comparison + +The current model hides the access structure but weakly protects the content. The proposed model exposes the structure but strongly protects the content: + +| Aspect | Current model (default: read) | Proposed model (default: none) | +|---|---|---| +| Content protection | Weak (any org member sees everything; one org invite = full access) | Strong (explicit team membership via reviewed PR required) | +| Structure visibility | Hidden (secret team, no public config) | Exposed (repo names, team memberships in public config) | +| Access change governance | None (manual, no review, no audit trail) | Full (PR-reviewed, drift-detected, git history) | +| Social engineering surface | All 32 org members are valid targets | Only team members are valid targets (smaller set) | +| Accidental exposure risk | High (new org member immediately sees private repos) | Low (requires explicit team addition via PR) | + +**Conclusion**: The proposed model is strictly better from a sensitive information protection standpoint. The trade-off is exposing organizational metadata (repo names, team structure) in the public config, which is low-risk provided naming and description conventions are followed. + +### Access gap during migration + +**Risk**: If the default permission is changed before teams are created and populated, members lose access to private repos. + +**Mitigation**: Strict two-phase sequencing. Teams are created and verified in Phase 1. The default permission is changed only in Phase 2, after Phase 1 is confirmed working. Each phase is a separate PR. + +### Secret team cleanup ordering + +**Risk**: If `--ignore-secret-teams` is removed before the `nunya-access` secret team is deleted from GitHub, peribolos will see an undeclared team and attempt to delete it on the next run. + +**Mitigation**: Delete the `nunya-access` secret team manually from GitHub only after confirming that closed-team access is working correctly. Remove `--ignore-secret-teams` from the workflows in the same PR or immediately after. + +### Stakeholder access over-provisioning + +**Risk**: All 19 currently teamless members are added to `private-repos-readers` to preserve existing access, but not all of them may need it. + +**Mitigation**: This is an intentional temporary measure. A follow-up review of the `private-repos-readers` membership should be planned to remove unnecessary access. The PR-based model makes this easy -- just submit a PR removing members from the team. + +## Open Questions + +1. Should private repo descriptions in `peribolos.yaml` be omitted or set to generic text to minimize exposure? +2. Are there members among the 19 stakeholders who are known to NOT need private repo access and can be excluded from the initial `private-repos-readers` team? +3. Is there a timeline for onboarding external contributors that drives urgency for this change? +4. Are the `private-repos-maintainers` actually needed, or are admins sufficient for the maintain-level responsibilities on private repos? diff --git a/openspec/changes/restrict-private-repo-access/proposal.md b/openspec/changes/restrict-private-repo-access/proposal.md new file mode 100644 index 0000000..bd8a1cc --- /dev/null +++ b/openspec/changes/restrict-private-repo-access/proposal.md @@ -0,0 +1,36 @@ +## Why + +The complytime GitHub organization currently sets `default_repository_permission: read`, which grants every org member implicit read access to all repositories, including private ones (nunya, roadmap). Today all org members are from the same company, so this is acceptable. However, the organization is preparing to onboard external contributors for its open-source projects. Once external members join, they will automatically gain read access to private repositories containing sensitive information. The org-wide default must be restricted before that happens. + +## What Changes + +- Change `default_repository_permission` from `read` to `none` in `peribolos.yaml`. This removes implicit access to private repositories for all org members. Public repositories remain unaffected (visible to anyone on the internet). +- Add private repositories (nunya, roadmap) to the `repos` section of `peribolos.yaml` so their settings are managed as code alongside all other org repositories. +- Create closed (not secret) teams in `peribolos.yaml` to grant explicit access to private repositories at appropriate permission levels (read, write, maintain). This replaces the current manually-managed secret team (`nunya-access`) with a codified, PR-reviewed, drift-detected model. +- Remove the `--ignore-secret-teams` flag from peribolos workflows once all private repo access is managed through closed teams in the config. The flag was originally added to prevent peribolos from stripping permissions from the manually-managed `nunya-access` secret team. + +## Capabilities + +### New Capabilities + +- `private-repo-access-control`: Defines how access to private repositories is granted, what information is exposed in the public org config, the team structure for permission levels, and the sequencing required to avoid access gaps during migration. + +### Modified Capabilities + +(none) + +## Impact + +### Files directly affected + +- `peribolos.yaml` -- org default permission, new repo entries, new team definitions +- `.github/workflows/peribolos-apply.yml` -- remove `--ignore-secret-teams` flag +- `.github/workflows/peribolos-drift.yml` -- remove `--ignore-secret-teams` flag +- `MAINTAINING.md` -- document private repo access procedures + +### Risks + +- **Information exposure**: Adding private repos to `peribolos.yaml` (which lives in the public `.github` repo) reveals repo names, descriptions, and team memberships. The actual content of private repos remains private. See the spec for a detailed breakdown of what is newly exposed. +- **Access gap during migration**: If the org default is changed to `none` before team-based access is in place, org members will temporarily lose access to private repos. Sequencing is critical -- teams must be created and populated before the default is changed. +- **Stakeholder access disruption**: 19 org members (managers, stakeholders) currently have no team membership and rely entirely on the org-wide `default_repository_permission: read` for access. These members must be added to the appropriate private-repo team before the default is changed. +- **Secret team cleanup**: The existing `nunya-access` secret team must be retired after migration. If `--ignore-secret-teams` is removed while a secret team still exists with repo permissions, peribolos will attempt to delete it on the next run. diff --git a/openspec/changes/restrict-private-repo-access/specs/private-repo-access-control/spec.md b/openspec/changes/restrict-private-repo-access/specs/private-repo-access-control/spec.md new file mode 100644 index 0000000..f5ab59d --- /dev/null +++ b/openspec/changes/restrict-private-repo-access/specs/private-repo-access-control/spec.md @@ -0,0 +1,181 @@ +## ADDED Requirements + +### Requirement: Org default permission SHALL be none + +The organization `default_repository_permission` in `peribolos.yaml` SHALL be set to `none`. This ensures that org membership alone does not grant access to any repository. Access to private repositories SHALL be granted exclusively through team membership or admin role. + +#### Scenario: External contributor joins the org + +- **WHEN** an external contributor is added to the `members` list in `peribolos.yaml` +- **THEN** the contributor SHALL have no access to private repositories (nunya, roadmap) unless explicitly added to a team that grants access to those repositories + +#### Scenario: Existing org member without team membership + +- **WHEN** an org member has no team membership and the default permission is `none` +- **THEN** the member SHALL still be able to view, clone, fork, and open issues on all public repositories (public repos are visible to anyone on the internet) +- **AND** the member SHALL have no access to private repositories unless added to an appropriate team + +#### Scenario: Engineer with team membership on public repos + +- **WHEN** an engineer is a member of a closed team (e.g., `complytime-dev`) that grants write access to public repos +- **AND** the org default permission is `none` +- **THEN** the engineer's write access to those public repos SHALL be unchanged (team grants override the base permission upward) + +### Requirement: Private repos SHALL be declared in peribolos config + +All private repositories in the complytime organization SHALL be listed in the `repos` section of `peribolos.yaml` with at minimum the following fields: `default_branch`, `has_projects`, and `private: true`. + +#### Scenario: Private repo entry in peribolos.yaml + +- **WHEN** a private repository (e.g., nunya) is added to the `repos` section of `peribolos.yaml` +- **THEN** the entry SHALL include `private: true` to ensure peribolos does not change the repo's visibility +- **AND** the repo description field MAY be omitted or set to generic text to minimize information exposure in the public config + +#### Scenario: Peribolos reconciliation of private repos + +- **WHEN** peribolos runs with `--fix-repos` +- **THEN** private repos listed in `peribolos.yaml` SHALL have their settings reconciled like any other repo +- **AND** peribolos SHALL NOT change the `private` flag to `false` unless `--allow-repo-publish` is explicitly set (this flag is not used in the current workflow) + +### Requirement: Access to private repos SHALL be granted through closed teams + +Access to private repositories SHALL be managed through closed (not secret) teams declared in `peribolos.yaml`. Teams SHALL be organized by access role, not by individual repository. + +The following team structure SHALL be used: + +- `private-repos-readers`: grants `read` access to all private repositories +- `private-repos-writers`: grants `write` access to all private repositories (if needed beyond the readers team) +- `private-repos-maintainers`: grants `maintain` access to all private repositories (if needed beyond admin access) + +Team membership and repo mappings SHALL be declared in `peribolos.yaml` and managed through the standard PR review process. + +#### Scenario: Manager needs read access to all private repos + +- **WHEN** a manager or stakeholder needs to view content in private repositories +- **THEN** an admin SHALL add the person's GitHub username to the `members` list of the `private-repos-readers` team in `peribolos.yaml` +- **AND** the change SHALL go through the standard PR review process before being merged + +#### Scenario: Engineer needs write access to a private repo + +- **WHEN** an engineer needs to push commits to a private repository +- **THEN** an admin SHALL add the person to the `private-repos-writers` team in `peribolos.yaml` +- **AND** that person SHALL also have read access through the "highest wins" principle (write implies read) + +#### Scenario: New private repo is created in the org + +- **WHEN** a new private repository is created in the complytime organization +- **THEN** the repo SHALL be added to the `repos` section of `peribolos.yaml` with `private: true` +- **AND** the repo SHALL be added to the `repos` map of the appropriate private-repo teams (readers, writers, maintainers) based on who needs access + +### Requirement: Migration SHALL preserve existing access + +The migration from the current access model (org-wide read default + secret team) to the new model (none default + closed teams) SHALL NOT cause any member to lose access to private repositories, even temporarily. + +#### Scenario: Phase 1 -- teams created before default changes + +- **WHEN** Phase 1 is applied (new teams and private repo entries added to `peribolos.yaml`) +- **THEN** all current org members who have access to private repos (via the org-wide read default) SHALL be listed in the `private-repos-readers` team (or a higher-privilege team) +- **AND** peribolos SHALL create the teams and set repo permissions before Phase 2 begins + +#### Scenario: Phase 2 -- default changed after teams are confirmed + +- **WHEN** Phase 2 is applied (default_repository_permission changed to `none`) +- **THEN** members in the `private-repos-readers` team SHALL retain read access to private repos through their team membership +- **AND** members NOT in any private-repo team SHALL lose access to private repos (this is the intended behavior) + +#### Scenario: Verification between phases + +- **WHEN** Phase 1 has been merged and peribolos has run +- **THEN** an admin SHALL verify that team-based access is working correctly before proceeding to Phase 2 +- **AND** verification SHALL include confirming that at least one member of `private-repos-readers` can access the private repos + +### Requirement: Secret team and workaround SHALL be retired + +After the migration is complete and verified, the `nunya-access` secret team SHALL be deleted from GitHub, and the `--ignore-secret-teams` flag SHALL be removed from peribolos workflows. + +#### Scenario: Secret team removal after migration + +- **WHEN** Phase 2 is complete and verified (closed teams are providing access, default is `none`) +- **THEN** an admin SHALL manually delete the `nunya-access` secret team from the GitHub UI +- **AND** the `--ignore-secret-teams` flag SHALL be removed from `peribolos-apply.yml` and `peribolos-drift.yml` + +#### Scenario: Peribolos reconciliation after flag removal + +- **WHEN** `--ignore-secret-teams` is removed from peribolos workflows +- **AND** no secret teams exist in the org +- **THEN** peribolos reconciliation SHALL behave identically to before (no secret teams to process) + +#### Scenario: Unauthorized secret team creation detected + +- **WHEN** `--ignore-secret-teams` has been removed +- **AND** someone manually creates a secret team in the GitHub UI +- **THEN** peribolos SHALL detect the undeclared team and attempt to delete it on the next run (standard reconciliation behavior) + +### Requirement: Private repo names SHALL follow opaque naming conventions + +Private repository names appear in the public `peribolos.yaml` config. To prevent information leakage through repo names, private repos SHALL use opaque or generic names that do not reveal the repository's purpose, contents, or strategic intent. + +#### Scenario: Acceptable private repo names + +- **WHEN** a new private repository is created in the complytime organization +- **THEN** the repository name SHALL be opaque (e.g., "nunya", "internal-tools") or generic (e.g., "private-project-1") +- **AND** the name SHALL NOT contain references to specific security vulnerabilities (e.g., "cve-2026-xxxx-response"), strategic initiatives (e.g., "acquisition-analysis"), confidential partnerships, or internal organizational matters + +#### Scenario: Reviewing private repo names before adding to config + +- **WHEN** a private repo is being added to `peribolos.yaml` +- **THEN** the PR reviewer SHALL verify that the repo name does not reveal sensitive information about the repo's purpose or contents + +### Requirement: Private repo descriptions SHALL NOT leak sensitive information + +The `description` field in `peribolos.yaml` is optional but visible in the public config. For private repositories, descriptions SHALL be omitted or set to generic text to prevent information leakage. + +#### Scenario: Description omitted + +- **WHEN** a private repo entry is added to `peribolos.yaml` without a `description` field +- **THEN** peribolos SHALL leave the repo's existing GitHub description unchanged +- **AND** no descriptive information about the repo SHALL appear in the public config + +#### Scenario: Generic description provided + +- **WHEN** a private repo entry includes a `description` field +- **THEN** the description SHALL use generic, non-revealing text (e.g., "Internal project repository") +- **AND** the description SHALL NOT contain sensitive project details, client names, security-related information, unannounced product plans, or references to specific individuals or organizations + +#### Scenario: PR review catches sensitive description + +- **WHEN** a PR adds or modifies a private repo description in `peribolos.yaml` +- **THEN** the PR reviewer SHALL verify the description does not reveal sensitive information before approving + +### Requirement: Public config exposure SHALL be documented and bounded + +The `peribolos.yaml` file resides in a public repository. Adding private repo configuration to this file exposes certain organizational metadata. The exposure SHALL be explicitly documented and bounded. + +#### Scenario: Information that is exposed + +- **WHEN** private repos are added to `peribolos.yaml` +- **THEN** the following information SHALL be visible in the public `.github` repository: + - Private repository names + - Private repository descriptions (if set) + - That the repositories are private (`private: true`) + - Team names and membership lists for private-repo teams + - Permission levels granted to each team on each private repo + - Git history of all access changes (PR history) + +#### Scenario: Information that remains private + +- **WHEN** private repos are added to `peribolos.yaml` +- **THEN** the following information SHALL remain inaccessible to non-authorized users: + - Repository contents (source code, files, documents) + - Issues, pull requests, and discussions within private repos + - Actions workflow runs and logs within private repos + - Branch protection rules and other repo-level settings not managed by peribolos + +#### Scenario: Net security posture improvement + +- **WHEN** the migration from `default_repository_permission: read` to `none` with closed teams is complete +- **THEN** the overall security posture SHALL be improved: + - Content protection is strengthened (explicit team membership required vs. implicit org-wide read) + - Accidental exposure risk is reduced (new org members cannot see private repos by default) + - Access governance is added (PR-reviewed changes with git audit trail vs. manual untracked changes) +- **AND** the trade-off of exposing organizational metadata (repo names, team structure) in the public config SHALL be accepted as low-risk provided the naming and description conventions defined in this spec are followed diff --git a/openspec/changes/restrict-private-repo-access/tasks.md b/openspec/changes/restrict-private-repo-access/tasks.md new file mode 100644 index 0000000..1ef849d --- /dev/null +++ b/openspec/changes/restrict-private-repo-access/tasks.md @@ -0,0 +1,33 @@ +## 1. Phase 1 -- Add private repos and teams to peribolos config + +- [ ] 1.1 Add nunya to the `repos` section of `peribolos.yaml` with `default_branch: main`, `has_projects: true`, and `private: true`. Omit or use a generic description. +- [ ] 1.2 Add roadmap to the `repos` section of `peribolos.yaml` with `default_branch: main`, `has_projects: true`, and `private: true`. Omit or use a generic description. +- [ ] 1.3 Create the `private-repos-readers` closed team in `peribolos.yaml` with read access to nunya and roadmap. Add all 19 currently teamless members plus any other members who need read access. +- [ ] 1.4 Create the `private-repos-writers` closed team in `peribolos.yaml` with write access to nunya and roadmap (if there are members who need write but are not admins). Skip if not needed. +- [ ] 1.5 Create the `private-repos-maintainers` closed team in `peribolos.yaml` with maintain access to nunya and roadmap (if there are members who need maintain but are not admins). Skip if not needed. +- [ ] 1.6 Run `make peribolos-dryrun` to validate the config and preview changes. +- [ ] 1.7 Open Phase 1 PR, get admin review, and merge. +- [ ] 1.8 Verify peribolos has run successfully after merge (check GitHub Actions log for `peribolos-apply` workflow). +- [ ] 1.9 Verify that members of `private-repos-readers` can access nunya and roadmap through team-based access. + +## 2. Phase 2 -- Change org default permission + +- [ ] 2.1 Change `default_repository_permission` from `read` to `none` in `peribolos.yaml`. +- [ ] 2.2 Run `make peribolos-dryrun` to validate and preview the change. +- [ ] 2.3 Open Phase 2 PR, get admin review, and merge. +- [ ] 2.4 Verify peribolos has run successfully after merge. +- [ ] 2.5 Verify that members of `private-repos-readers` still have access to private repos. +- [ ] 2.6 Verify that an org member NOT in any private-repo team cannot access nunya or roadmap. + +## 3. Retire secret team and workaround + +- [ ] 3.1 Manually delete the `nunya-access` secret team from the GitHub UI (Settings > Teams). +- [ ] 3.2 Remove `--ignore-secret-teams` from `PERIBOLOS_ARGS` in `.github/workflows/peribolos-apply.yml`. +- [ ] 3.3 Remove `--ignore-secret-teams` from the peribolos command in `.github/workflows/peribolos-drift.yml`. +- [ ] 3.4 Open Phase 3 PR with the workflow changes, get admin review, and merge. +- [ ] 3.5 Verify peribolos runs successfully without the `--ignore-secret-teams` flag. + +## 4. Documentation + +- [ ] 4.1 Update `MAINTAINING.md` to document the procedure for granting a person access to a private repository (add to appropriate team via PR). +- [ ] 4.2 Update `MAINTAINING.md` to document the procedure for adding a new private repository to the org (add to `peribolos.yaml` repos section and to relevant team repos maps).