summaryrefslogtreecommitdiffhomepage
path: root/.github/workflows/vouch-check-issue.yml
blob: 94569f47312ad183c118c0bf7c2451404f5fa790 (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
94
95
96
name: vouch-check-issue

on:
  issues:
    types: [opened]

permissions:
  contents: read
  issues: write

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - name: Check if issue author is denounced
        uses: actions/github-script@v7
        with:
          script: |
            const author = context.payload.issue.user.login;
            const issueNumber = context.payload.issue.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 issue.`);
              return;
            }

            // Author is denounced — close the issue
            const body = 'This issue has been automatically closed.';

            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: issueNumber,
              body,
            });

            await github.rest.issues.update({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: issueNumber,
              state: 'closed',
              state_reason: 'not_planned',
            });

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