Skip to content

Update Access Controls - SIMD-0007 #320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
112 changes: 112 additions & 0 deletions .github/workflows/require-jump-anza.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Require Jump + Anza approval

on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
- converted_to_draft
pull_request_review:
types: [submitted, dismissed, edited]

permissions:
contents: read
pull-requests: read

jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Verify Jump + Anza approvals
uses: actions/github-script@v7
with:
script: |
// github, context, core are injected by github-script

// ──────────── 1. MANUAL ROSTERS ────────────
const jumpApprovers = ['taffet-jump', 'topointon-jump', '0x0ece', 'lidatong', 'benhawkins18', 'jacobcreech'];
const anzaApprovers = ['t-nelson', 'sakridge', 'bw-solana', 'benhawkins18', 'jacobcreech'];
// ───────────────────────────────────────────

const pr = context.payload.pull_request;
if (!pr) { core.setFailed('No pull_request context'); return; }

// 2. fetch *all* reviews on this PR
const { data: reviews } = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
per_page: 100
});

// DEBUG 1: raw events
core.info('=== Raw review events ===');
reviews.forEach(r =>
core.info(`${r.user.login} -> ${r.state} @ ${r.submitted_at}`));

// 3. determine effective state per reviewer
// We replay events chronologically so DISMISSED or REQUEST_CHANGES
// can override an earlier APPROVED.
reviews.sort((a, b) => new Date(a.submitted_at) - new Date(b.submitted_at));

const status = {}; // login → {approved, blocked}
for (const r of reviews) {
const u = r.user.login;
status[u] = status[u] || { approved: false, blocked: false };

switch (r.state) {
case 'APPROVED':
status[u].approved = true;
status[u].blocked = false;
break;
case 'REQUEST_CHANGES':
status[u].approved = false;
status[u].blocked = true; // blocks until new approval
break;
case 'DISMISSED':
status[u].approved = false; // previous approval is now void
break;
default:
// COMMENTED etc – ignore
}
}

// DEBUG 2: effective map
core.info('=== Effective state per reviewer ===');
Object.entries(status).forEach(([u, s]) =>
core.info(`${u}: approved=${s.approved}, blocked=${s.blocked}`));

// 4. final approved list (approved && not blocked)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a single block from a group member should override all approvers from that group. Right now you could have a situation where a group member approves and another member of the same group requests changes and the result is that the group check passes.

const approved = Object.entries(status)
.filter(([_, s]) => s.approved && !s.blocked)
.map(([u]) => u);

core.info(`Approved reviewers counted: ${approved.join(', ') || 'none'}`);

// 5. org-level checks
const hasJump = jumpApprovers.some(u => approved.includes(u));
const hasAnza = anzaApprovers.some(u => approved.includes(u));

// helpful failure message
const missingMsgs = [];
if (!hasJump)
missingMsgs.push(`Jump approval missing, need one of: ${jumpApprovers.join(', ')}`);
if (!hasAnza)
missingMsgs.push(`Anza approval missing, need one of: ${anzaApprovers.join(', ')}`);

// PR-check summary
core.summary
.addHeading('Jump + Anza approval check')
.addTable([
['Jump approval', hasJump ? '✅' : '❌'],
['Anza approval', hasAnza ? '✅' : '❌']
])
.write();

if (missingMsgs.length) {
core.setFailed(missingMsgs.join(' | '));
} else {
core.notice('All required approvals present; merge allowed.');
}
166 changes: 49 additions & 117 deletions proposals/0007-access-policy.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
simd: '0007'
simd: "0007"
title: SIMD Access Policy
authors:
- Jacob Creech (Solana Foundation)
Expand All @@ -12,148 +12,80 @@

## Summary

3 levels of access, in the order of increasing access:
Two levels of access, listed in order of increasing privilege:

1. Triage
1. **Write**
2. **Maintain**

Requirement: One voucher from anyone with level 2 or above access.

2. Write

Requirement: One voucher from anyone with level 3 access or two from
anyone with level 2 access. If only vouched by those with level 2 access, the
user must have Triage access to be promoted.

3. Maintain

Requirement: One voucher from anyone with level 3 access. This permission
is usually reserved for those maintaining the SIMD process.

Each of the levels implies having the previous levels - e.g. level 2 implies
level 1. A contributor with Write access will be able to triage pull requests
in accordance with Github access policies.
Each level implies the capabilities of the one beneath it. A contributor with
_Write_ access can triage, approve, and merge pull requests once required
status‑checks pass, while a contributor with _Maintain_ access can additionally
administer repository settings and manage access.

## Motivation

Shamelessly borrowing from [Mozilla's access
policy](https://www.mozilla.org/en-US/about/governance/policies/commit/access-policy/)
:

```
There are two sorts of control which can be used to stop people checking in -
technical and social.

A "full technical" implementation would have per-directory permissions
everywhere, but would lead to a greatly-increased management overhead for IT,
vouchers and developers alike.
A "full social" implementation would just have a single permission which gave
you complete access to everything, but (depending on the height of the barrier
to that permission) there is a risk of making developer's lives more difficult
when they are excluded, or of giving the untrustworthy or incompetent power to
mess things up.
Therefore, a good policy balances the use of technical and social controls to
minimize both management overhead and risk to the development process.
```
The SIMD process values openness while safeguarding core infrastructure. Two
clearly‑defined levels minimise administrative overhead yet retain sufficient
control to keep the repository healthy.

## Alternatives Considered

[EIP](https://github.com/ethereum/EIPs) run under two separate levels,
contributors and editors. Editors are a select group of people that review each
EIP and have write access. Instead of starting with a select group of editors
who have exclusive write access, we could begin with an easier way to achieve
write access and gradually tighten permissions as needed.

[RFCs](https://www.rust-lang.org/governance) have sub-teams that review and
triage new proposed changes. This is a possibility, but would require more
granular labeling of different SIMDs.

[PEP](https://peps.python.org/pep-0013/) has an election of a council that
reviews and triages new proposed changes. The PEP approach may result in an
increase in governance overhead.
* A three‑tier scheme (Triage / Write / Maintain) was previously documented.
Consolidating Triage and Write avoids confusion and matches GitHub’s current
merge‑gate automation where contributors need _Write_ to land changes.
* Other open‑source projects (e.g. EIP and PEP) use committee‑based models;
those approaches carry higher governance overhead for our current scale.

## Detailed Design

### Level 1 - Triage Access

Requirements: One voucher from any user with level 2 or above access.
### Level 1 – Write Access

Contributors with Triage access will have the associated [triage Github access
policy](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
for the [Solana Improvement
Documents](https://github.com/solana-foundation/solana-improvement-documents)
repository.
**Requirement**  One voucher from a Level 2 member **or** two vouchers from
existing Level 1 members.

### Level 2 - Write Access
Write maps to GitHub’s built‑in [**Write** role](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role):

Requirements: One voucher from anyone with level 3 access or two vouchers from
anyone from level 2. Applicants must have level 1 access to apply for level 2.
* Open pull requests and **self‑merge** once mandatory status checks (e.g. Jump + Anza approvals) are green. Write‑level contributors may not merge pull requests opened by other users; that capability is reserved for Level 2 maintainers.

Check failure on line 48 in proposals/0007-access-policy.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 237]

proposals/0007-access-policy.md:48:81 MD013/line-length Line length [Expected: 80; Actual: 237]
* Manage issues, labels, and project boards.
* Create and push branches.

Contributors with Write access will have the associated [write Github access
policy](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
for the [Solana Improvement
Documents](https://github.com/solana-foundation/solana-improvement-documents)
repository.
### Level 2 – Maintain Access

Most notably these permissions allow the contributor to approve and merge pull
requests.
**Requirement**  One voucher from an existing Level 2 member.

### Level 3 - Maintain Access
Maintain maps to GitHub’s [**Maintain** role](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role):

Requirements: One voucher from anyone with level 3 access.
* All capabilities of Level 1, **plus the ability to merge any pull request** once required status checks are satisfied.

Check failure on line 58 in proposals/0007-access-policy.md

View workflow job for this annotation

GitHub Actions / Markdown Linter

Line length [Expected: 80; Actual: 120]

proposals/0007-access-policy.md:58:81 MD013/line-length Line length [Expected: 80; Actual: 120]
* Manage repository settings, branch‑protection rules, and workflows.
* Grant or revoke Write and Maintain access according to this SIMD.

Contributors will have the associated [maintain Github access
policy](https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role)
for the [Solana Improvement
Documents](https://github.com/solana-foundation/solana-improvement-documents)
repository.
### Vouching Process

Users with Maintain access are responsible for managing the SIMD repository and
granting user access based on the above requirements.

### Vouching Process

To receive a level of access as defined in SIMD-0007, follow these steps:

1. Open an issue on the [Solana Improvement
Documents](https://github.com/solana-foundation/solana-improvement-documents)
repository with a title in the following format: "Request Access (Level [X])
for [Username]". Add information that can help identify you such as your
discord id in the issue.
2. Gather your vouchers to add a comment on the issue expressing their support.
3. Once the issue has received enough support, notify the users with Maintain
access by adding a comment tagging
[`@SIMD-Maintainers`](https://github.com/orgs/solana-foundation/teams/simd-maintainers)
and you will be granted the requested level of access.
1. Open an issue in the SIMD repository titled
`Request Access (Level X) for <GitHub‑username>` and include a public contact
method (e.g. Discord handle).
2. Supporters comment **“I vouch”** on the issue.
3. When the issue meets the requirement above, a Level 2 maintainer adds the
user to the appropriate GitHub team.

### Access Removal Process

In the event that a user requires their access to be removed, follow these
steps:

1. Open an issue on the [Solana Improvement
Documents](https://github.com/solana-foundation/solana-improvement-documents)
repository with the title in the following format: "Revoke Access (Level X) for
[Username]".
2. Other users with the appropriate level of access should comment on the issue
to express their support for the removal of access.
3. Once the issue has received enough support, the user's access will be
revoked.

Requirements:

- If a user's level 3 access is being revoked, support from at least two other
users with level 3 access is required.
- If a user's level 1 or 2 access is being revoked, support from at least two
other users with level 2 or one user with level 3 is required.
- If a user opens the issue to revoke their own access, no support from others
is required.
1. Open an issue titled `Revoke Access (Level X) for <GitHub‑username>`.
2. Collect supporting comments:
* Revoking **Level 2** – requires support from two other Level 2 members.
* Revoking **Level 1** – requires support from one Level 2 member **or** two
Level 1 members.
* Self‑revocation needs no additional support.
3. A Level 2 maintainer removes the user from the corresponding team.

## Impact

Setting a permissive way of contributing to the SIMD process will help remove
engineering overhead.
A lean two‑tier policy lowers the barrier to contribution while preserving
clear custodianship of the SIMD process.

## Security Considerations

In the event of a malicious actor gaining any level of access, users must
follow the Access Removal Process to revoke that actor's access.
Should a malicious actor gain access, community members must invoke the Access
Removal Process promptly. Maintainers may also tighten branch‑protection rules
or revoke credentials as warranted.

Loading