Skip to content
Back to skills

Approval Checker

ASecurity

Verifies that an authorized user has approved the fix plan before proceeding with implementation.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
securitypythongobashreacttestinggitapisecurity

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill approval-checker --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Approval Checker?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Approval Checker
[![Security: A โ€” Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-approval-checker/badge)](https://www.skillsdirectory.com/skills/david-li0406-approval-checker)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: approval-checker
description: Verifies that an authorized user has approved the fix plan before proceeding with implementation.
---

## Purpose

Check for:
1. Thumbs-up (๐Ÿ‘) reaction on plan comment
2. "Approve" keyword in reply comments
3. User is authorized (maintainer/admin)

Only authorized approvals count - ignore others safely.

## Usage

Include this file when checking approval:

```
Use lib/approval-checker to verify approval before implementing
```

## Authorization

### Who Can Approve?

Users with **push** or **admin** permissions on the repository.

```bash
gh api repos/{owner}/{repo}/collaborators \
  --jq '[.[] | select(.permissions.push == true or .permissions.admin == true) | .login]'
```

**Example output:**
```json
["alice", "bob", "charlie"]
```

These are the authorized approvers.

### Why This Matters

Security: Prevents unauthorized code changes.

**Scenario:**
- External contributor comments "approve" โ†’ Ignored (not authorized)
- Repository maintainer clicks ๐Ÿ‘ โ†’ Accepted (authorized)

## Approval Methods

### Method 1: Thumbs Up Reaction (๐Ÿ‘)

User clicks thumbs-up on the plan comment.

**Check:**
```bash
# Get plan comment ID from previous step
COMMENT_ID=<plan-comment-id>

# Fetch reactions
gh api repos/{owner}/{repo}/issues/comments/${COMMENT_ID}/reactions \
  --jq '.[] | select(.content == "+1") | .user.login'
```

**Output:** List of usernames who reacted with ๐Ÿ‘

**Logic:**
```python
reactions = get_thumbs_up_reactions(comment_id)
authorized = get_authorized_users()

for user in reactions:
    if user in authorized:
        return {"approved": True, "approver": user, "method": "reaction"}

return {"approved": False}
```

### Method 2: Approval Comment

User replies with "approve", "approved", "lgtm", or "go ahead" (case-insensitive).

**Check:**
```bash
# Get all comments after the plan was posted
PLAN_TIMESTAMP="2026-01-16T10:00:00Z"

gh issue view <issue-number> --json comments \
  --jq '.comments[] | select(.createdAt > "'$PLAN_TIMESTAMP'") | {author: .author.login, body: .body}'
```

**Output:** Recent comments with author and body

**Logic:**
```python
import re

approval_keywords = ["approve", "approved", "lgtm", "go ahead"]
pattern = re.compile(r'\b(' + '|'.join(approval_keywords) + r')\b', re.IGNORECASE)

comments = get_comments_after(plan_timestamp)
authorized = get_authorized_users()

for comment in comments:
    if comment.author in authorized:
        if pattern.search(comment.body):
            return {"approved": True, "approver": comment.author, "method": "comment"}

return {"approved": False}
```

## Implementation Steps

### Step 1: Get Repository Info

```bash
# Extract owner and repo from git remote
REMOTE=$(git remote get-url origin)
# Parse: https://github.com/owner/repo.git or git@github.com:owner/repo.git

OWNER=$(echo $REMOTE | sed -E 's/.*github\.com[:/]([^/]+).*/\1/')
REPO=$(echo $REMOTE | sed -E 's/.*github\.com[:/][^/]+\/([^.]+).*/\1/')
```

### Step 2: Get Authorized Users

```bash
gh api repos/${OWNER}/${REPO}/collaborators \
  --jq '[.[] | select(.permissions.push == true or .permissions.admin == true) | .login]' \
  > /tmp/authorized_users.json
```

### Step 3: Find Plan Comment

```bash
gh issue view <issue-number> --json comments \
  --jq '.comments[] | select(.body | contains("๐Ÿค– Automated Fix Plan")) | {id: .id, createdAt: .createdAt}'
```

**Output:**
```json
{
  "id": "IC_kwDOA...",
  "createdAt": "2026-01-16T10:00:00Z"
}
```

### Step 4: Check Method 1 (Reactions)

```bash
COMMENT_ID="IC_kwDOA..."

gh api repos/${OWNER}/${REPO}/issues/comments/${COMMENT_ID}/reactions \
  --jq '.[] | select(.content == "+1") | .user.login' \
  > /tmp/reactions.txt
```

Check if any reactor is in authorized users:

```bash
while read user; do
  if grep -q "\"$user\"" /tmp/authorized_users.json; then
    echo "APPROVED by $user via reaction"
    exit 0
  fi
done < /tmp/reactions.txt
```

### Step 5: Check Method 2 (Comments)

```bash
PLAN_TIMESTAMP="2026-01-16T10:00:00Z"

gh issue view <issue-number> --json comments \
  --jq '.comments[] | select(.createdAt > "'$PLAN_TIMESTAMP'") | {author: .author.login, body: .body}' \
  > /tmp/recent_comments.json
```

Check for approval keywords from authorized users:

```bash
jq -r '.[] | "\(.author)|\(.body)"' /tmp/recent_comments.json | while IFS='|' read author body; do
  # Check if author is authorized
  if grep -q "\"$author\"" /tmp/authorized_users.json; then
    # Check for approval keywords (case-insensitive)
    if echo "$body" | grep -iE '\b(approve|approved|lgtm|go ahead)\b' > /dev/null; then
      echo "APPROVED by $author via comment"
      exit 0
    fi
  fi
done
```

### Step 6: Not Approved Response

If no approval found after checking both methods:

```bash
gh issue comment <issue-number> --body "โš ๏ธ **Approval Required**

No approval detected yet. To proceed:
- ๐Ÿ‘ Add thumbs up reaction to the plan comment above, OR
- ๐Ÿ’ฌ Reply with 'approve' or 'lgtm'

Note: Only repository maintainers can approve.

Current authorized approvers: $(cat /tmp/authorized_users.json | jq -r '.[] | "@" + .')"
```

**Example output:**
```
โš ๏ธ **Approval Required**

No approval detected yet. To proceed:
- ๐Ÿ‘ Add thumbs up reaction to the plan comment above, OR
- ๐Ÿ’ฌ Reply with 'approve' or 'lgtm'

Note: Only repository maintainers can approve.

Current authorized approvers: @alice @bob @charlie
```

## Output Format

Return approval status:

```json
{
  "approved": true,
  "approver": "alice",
  "method": "reaction",
  "timestamp": "2026-01-16T10:05:00Z"
}
```

Or:

```json
{
  "approved": false,
  "reason": "No approval from authorized users",
  "authorized_users": ["alice", "bob", "charlie"]
}
```

## Error Handling

### GitHub API Error

```bash
gh api repos/${OWNER}/${REPO}/collaborators 2>&1
```

If fails:

```markdown
โš ๏ธ **Approval Check Failed**

Couldn't verify approval due to API error:
\`\`\`
<error message>
\`\`\`

**Troubleshooting:**
1. Check GitHub CLI authentication: \`gh auth status\`
2. Verify repository access: \`gh repo view ${OWNER}/${REPO}\`
3. Try again: \`/continue-issue <issue-number>\`

If error persists, you can implement the plan manually.
```

### Plan Comment Not Found

```markdown
โš ๏ธ **Plan Comment Not Found**

Couldn't find the automated fix plan comment on this issue.

Did you run \`/handle-issue <issue-number>\` first?

**To proceed:**
1. Run \`/handle-issue <issue-number>\` to generate plan
2. Review and approve the plan
3. Run \`/continue-issue <issue-number>\`
```

### Multiple Approvals

If multiple authorized users approve:

```python
# Use first approval found (earliest timestamp)
approvals.sort(key=lambda x: x.timestamp)
return approvals[0]
```

## Integration with continue-issue

```markdown
1. Parse issue number
2. Check approval (lib/approval-checker) โ† YOU ARE HERE
3. If approved โ†’ Create worktree โ†’ Implement
4. If not approved โ†’ Post helpful message โ†’ Exit
```

**Flow:**
```
/continue-issue 42
    โ†“
Get authorized users from GitHub
    โ†“
Find plan comment
    โ†“
Check reactions (Method 1)
    โ†“
    โ”œโ”€ Approved โ†’ Proceed
    โ””โ”€ Not approved
        โ†“
    Check comments (Method 2)
        โ†“
        โ”œโ”€ Approved โ†’ Proceed
        โ””โ”€ Not approved โ†’ Post message โ†’ Exit
```

## Security Considerations

**No bypass mechanisms:**
- Can't override with flags
- Can't skip check
- Can't fake authorization

**Safe handling of unknowns:**
- Unknown users โ†’ Ignored
- Partial approval โ†’ Not sufficient
- Ambiguous comments โ†’ Not approved

**Principle:** Fail closed, not open.

## Testing Approach

**Test cases:**
1. โœ… Authorized user reacts ๐Ÿ‘ โ†’ Approved
2. โœ… Authorized user comments "approve" โ†’ Approved
3. โœ… Authorized user comments "LGTM" โ†’ Approved
4. โŒ Unauthorized user reacts ๐Ÿ‘ โ†’ Not approved
5. โŒ Unauthorized user comments "approve" โ†’ Not approved
6. โŒ Authorized user comments "looks good" โ†’ Not approved (no keyword)
7. โœ… Multiple approvals โ†’ Use first one
8. โŒ GitHub API error โ†’ Fail gracefully with message

## YAGNI Notes

**Not included:**
- Multi-level approval (single maintainer sufficient)
- Approval expiration (valid until revoked)
- Approval delegation (direct authorization only)
- Vote counting (single approval sufficient)

Keep it simple: one authorized approval proceeds.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading commentsโ€ฆ