summaryrefslogtreecommitdiffhomepage
path: root/.github/workflows/vouch-check-pr.yml
blob: 470b8e0a5ad787a67950732d46af0f7f49ecf68d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
name: vouch-check-pr

on:
  pull_request_target:
    types: [opened]

permissions:
  contents: read
  pull-requests: write

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Check if PR author is denounced
        uses: actions/github-script@v7
        with:
          script: |
            const author = context.payload.pull_request.user.login;
            const prNumber = context.payload.pull_request.number;

            // Skip bots
            if (author.endsWith('[bot]')) {
              core.info(`Skipping bot: ${author}`);
              return;
            }

            // Read the VOUCHED.td file via API (no checkout needed)
            let content;
            try {
              const response = await github.rest.repos.getContent({
                owner: context.repo.owner,
                repo: context.repo.repo,
                path: '.github/VOUCHED.td',
              });
              content = Buffer.from(response.data.content, 'base64').toString('utf-8');
            } catch (error) {
              if (error.status === 404) {
                core.info('No .github/VOUCHED.td file found, skipping check.');
                return;
              }
              throw error;
            }

            // Parse the .td file for denounced users
            const denounced = new Map();
            for (const line of content.split('\n')) {
              const trimmed = line.trim();
              if (!trimmed || trimmed.startsWith('#')) continue;
              if (!trimmed.startsWith('-')) continue;

              const rest = trimmed.slice(1).trim();
              if (!rest) continue;
              const spaceIdx = rest.indexOf(' ');
              const handle = spaceIdx === -1 ? rest : rest.slice(0, spaceIdx);
              const reason = spaceIdx === -1 ? null : rest.slice(spaceIdx + 1).trim();

              // Handle platform:username or bare username
              // Only match bare usernames or github: prefix (skip other platforms)
              const colonIdx = handle.indexOf(':');
              if (colonIdx !== -1) {
                const platform = handle.slice(0, colonIdx).toLowerCase();
                if (platform !== 'github') continue;
              }
              const username = colonIdx === -1 ? handle : handle.slice(colonIdx + 1);
              if (!username) continue;

              denounced.set(username.toLowerCase(), reason);
            }

            // Check if the author is denounced
            const reason = denounced.get(author.toLowerCase());
            if (reason === undefined) {
              core.info(`User ${author} is not denounced. Allowing PR.`);
              return;
            }

            // Author is denounced — close the PR
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber,
              body: 'This pull request has been automatically closed.',
            });

            await github.rest.pulls.update({
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: prNumber,
              state: 'closed',
            });

            core.info(`Closed PR #${prNumber} from denounced user ${author}`);