name: OpenClaw Gate on: issues: types: [opened] pull_request_target: types: [opened] jobs: check-contributor: runs-on: ubuntu-latest permissions: contents: read issues: write pull-requests: write steps: - name: Check contributor uses: actions/github-script@v7 with: script: | const isPR = !!context.payload.pull_request; const author = isPR ? context.payload.pull_request.user.login : context.payload.issue.user.login; const number = isPR ? context.payload.pull_request.number : context.payload.issue.number; const defaultBranch = context.payload.repository.default_branch; if (author.endsWith('[bot]') || author === 'dependabot[bot]') { console.log(`Skipping bot: ${author}`); return; } // --- Check APPROVED_CONTRIBUTORS --- async function getTextFile(path) { const { data } = await github.rest.repos.getContent({ owner: context.repo.owner, repo: context.repo.repo, path, ref: defaultBranch, }); if (!('content' in data) || typeof data.content !== 'string') { throw new Error(`Expected file content for ${path}`); } return Buffer.from(data.content, 'base64').toString('utf8'); } try { const content = await getTextFile('.github/APPROVED_CONTRIBUTORS'); const approved = content .split('\n') .map(l => l.trim().toLowerCase()) .filter(l => l && !l.startsWith('#')); if (approved.includes(author.toLowerCase())) { console.log(`${author} is in APPROVED_CONTRIBUTORS, passing`); return; } } catch (err) { console.log(`Could not read APPROVED_CONTRIBUTORS: ${err.message}`); } // --- Also pass collaborators with write+ access --- try { const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({ owner: context.repo.owner, repo: context.repo.repo, username: author, }); if (['admin', 'maintain', 'write'].includes(perm.permission)) { console.log(`${author} is a collaborator (${perm.permission}), passing`); return; } } catch { // not a collaborator } // --- Check if user opened issues/PRs on openclaw/openclaw --- async function hasOpenClawActivity(username) { try { const { data } = await github.rest.search.issuesAndPullRequests({ q: `repo:openclaw/openclaw author:${username}`, per_page: 1, }); if (data.total_count > 0) { console.log(`${username} has opened ${data.total_count} issues/PRs on openclaw/openclaw`); return true; } } catch (err) { console.log(`Search failed: ${err.message}`); } return false; } const hasActivity = await hasOpenClawActivity(author); if (!hasActivity) { console.log(`${author} has no openclaw/openclaw activity, passing`); return; } // --- Add openclaw label --- console.log(`${author} has openclaw/openclaw activity, adding label`); await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: number, labels: ['possibly-openclaw-clanker'], });