permissions and security - lukeocodes/wikiinator GitHub Wiki
The biggest issue we encountered was GitHub Actions having insufficient permissions to write to wiki repositories, even though the same token worked in regular workflows.
The problem:
- By default,
GITHUB_TOKEN
has read-only permissions - This is a security feature introduced to prevent accidental writes
- Wiki repositories require explicit write permissions
The symptom:
remote: Permission to user/repo.wiki.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/user/repo.wiki.git/': The requested URL returned error: 403
There are two levels of permissions configuration:
Settings → Actions → General → Workflow permissions
- Read repository contents and packages permissions (default)
- Read and write permissions ✅ (needed for wikis)
permissions:
contents: write # Required for wiki access
Important: Both levels must allow write access!
Instead of failing after doing all the work, we implemented early detection:
# Test permissions early with dry-run
permission_test_output=$(git push --dry-run 2>&1)
permission_test_exit_code=$?
if [ $permission_test_exit_code -ne 0 ]; then
if echo "$permission_test_output" | grep -q "403\|Permission.*denied\|not authorized"; then
echo "::error::Permission error detected early!"
echo "::error::Add 'permissions: contents: write' to your workflow"
exit 1
fi
fi
We learned to provide actionable error messages:
if echo "$push_output" | grep -q "403\|Permission.*denied\|not authorized"; then
log_error ""
log_error "🚨 PERMISSION ERROR DETECTED 🚨"
log_error ""
log_error "QUICK FIX: Add this to your workflow file:"
log_error ""
log_error "permissions:"
log_error " contents: write"
log_error ""
log_error "Example workflow:"
# ... provide complete example
fi
- Wikis are separate Git repositories (
.wiki.git
) - They require push access to update content
- Standard repository permissions don't automatically extend to wikis
- Git may not preserve authentication tokens after clone
- Solution: Re-set the remote URL before push operations
# Before pushing, ensure token is in remote URL
git remote set-url origin "https://x-access-token:${TOKEN}@github.com/${REPO}.wiki.git"
- Never log full tokens
- Use partial display for debugging:
${TOKEN:0:8}...
- Validate token presence early
- Use environment variables, not command-line arguments
- Only request
contents: write
(minimal needed permission) - Don't request broader permissions like
repo
unless absolutely necessary - Document exactly why each permission is needed
- Validate all user inputs
- Sanitize file paths
- Check for directory traversal attempts
# In your action.yml
permissions:
contents: write # Required for wiki repository access
- Test permissions immediately after clone
- Fail fast with clear error messages
- Provide copy-paste solutions
- Pattern match permission errors
- Differentiate between permission vs other errors
- Include troubleshooting links
- Minimal permissions required
- Safe token handling
- Input validation and sanitization
This approach ensures both security and user experience are optimized.