fix: security hardening batch 1 (SEC-002 through SEC-010) #99
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Vouch Check | |
| on: | |
| pull_request_target: | |
| types: [opened, reopened] | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| jobs: | |
| vouch-gate: | |
| if: github.repository_owner == 'NVIDIA' | |
| runs-on: ubuntu-latest | |
| env: | |
| ORG_READ_TOKEN: ${{ secrets.ORG_READ_TOKEN }} | |
| steps: | |
| - name: Check org membership | |
| id: org-check | |
| if: env.ORG_READ_TOKEN != '' | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.ORG_READ_TOKEN }} | |
| result-encoding: string | |
| script: | | |
| const author = context.payload.pull_request.user.login; | |
| try { | |
| const { status } = await github.rest.orgs.checkMembershipForUser({ | |
| org: context.repo.owner, | |
| username: author, | |
| }); | |
| if (status === 204 || status === 302) { | |
| console.log(`${author} is an org member. Skipping vouch check.`); | |
| return 'skip'; | |
| } | |
| } catch (e) { | |
| if (e.status !== 404) { | |
| console.log(`Org membership check error (status=${e.status}): ${e.message}`); | |
| } | |
| } | |
| return ''; | |
| - name: Check if contributor is vouched | |
| if: steps.org-check.outputs.result != 'skip' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const author = context.payload.pull_request.user.login; | |
| const authorType = context.payload.pull_request.user.type; | |
| // Skip bots (dependabot, renovate, github-actions, etc.). | |
| if (authorType === 'Bot') { | |
| console.log(`${author} is a bot. Skipping vouch check.`); | |
| return; | |
| } | |
| // Check the VOUCHED.td file on the dedicated "vouched" branch. | |
| // NOT the PR branch — the PR author could add themselves in their fork. | |
| let vouched = false; | |
| try { | |
| const { data } = await github.rest.repos.getContent({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| path: '.github/VOUCHED.td', | |
| ref: 'vouched', | |
| }); | |
| const content = Buffer.from(data.content, 'base64').toString('utf-8'); | |
| const usernames = content | |
| .split('\n') | |
| .map(line => line.trim()) | |
| .filter(line => line && !line.startsWith('#') && !line.startsWith('-')); | |
| vouched = usernames.some( | |
| name => name.toLowerCase() === author.toLowerCase() | |
| ); | |
| } catch (e) { | |
| console.log(`Could not read VOUCHED.td: ${e.message}`); | |
| } | |
| if (vouched) { | |
| console.log(`${author} is in VOUCHED.td. Approved.`); | |
| return; | |
| } | |
| // Not vouched — close the PR with an explanation. | |
| console.log(`${author} is not vouched. Closing PR.`); | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.payload.pull_request.number, | |
| body: [ | |
| `Thank you for your interest in contributing to OpenShell, @${author}.`, | |
| '', | |
| 'This project uses a **vouch system** for first-time contributors. Before submitting a pull request, you need to be vouched by a maintainer.', | |
| '', | |
| '**To get vouched:**', | |
| '1. Open a [Vouch Request](https://github.com/NVIDIA/OpenShell/discussions/new?category=vouch-request) discussion.', | |
| '2. Describe what you want to change and why.', | |
| '3. Write in your own words — do not have an AI generate the request.', | |
| '4. A maintainer will comment `/vouch` if approved.', | |
| '5. Once vouched, open a new PR (preferred) or reopen this one after a few minutes.', | |
| '', | |
| 'See [CONTRIBUTING.md](https://github.com/NVIDIA/OpenShell/blob/main/CONTRIBUTING.md#first-time-contributors) for details.', | |
| ].join('\n'), | |
| }); | |
| await github.rest.pulls.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: context.payload.pull_request.number, | |
| state: 'closed', | |
| }); |