Skip to content

fix(unsubscribe): replace in-memory rate limiter with Redis-backed generalLimiter #534

fix(unsubscribe): replace in-memory rate limiter with Redis-backed generalLimiter

fix(unsubscribe): replace in-memory rate limiter with Redis-backed generalLimiter #534

Workflow file for this run

name: PR Code Quality Checks
on:
pull_request:
branches: [main, master]
types: [opened, synchronize, reopened]
permissions: {}
jobs:
# ─────────────────────────────────────────
# 4. Security scan — detect common issues
# ─────────────────────────────────────────
security-scan:
name: Security Scan
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
return files.map(f => f.filename);
- name: Scan for hardcoded secrets patterns
id: secret-scan
run: |
echo "Scanning for potential secrets in changed files..."
ISSUES=""
# Check for common secret patterns
if git diff origin/main...HEAD -- '*.ts' '*.tsx' '*.js' | grep -E "(password|secret|api_key|apikey|token)\s*=\s*['\"][^'\"]{8,}" --include="*.ts" --include="*.tsx" -i; then
ISSUES="$ISSUES\n- Possible hardcoded secret detected"
fi
# Check for NEXT_PUBLIC_ on sensitive vars
if git diff origin/main...HEAD | grep -E "NEXT_PUBLIC_(DATABASE_URL|SECRET|PASSWORD|PRIVATE)" -i; then
ISSUES="$ISSUES\n- Sensitive variable exposed via NEXT_PUBLIC_ prefix"
fi
# Check for console.log with sensitive data patterns
if git diff origin/main...HEAD -- '*.ts' '*.tsx' | grep -E "console\.(log|error)\(.*?(password|token|secret|key)" -i; then
ISSUES="$ISSUES\n- Possible sensitive data in console.log"
fi
if [ -n "$ISSUES" ]; then
echo "security_issues=true" >> $GITHUB_OUTPUT
echo "issues=$ISSUES" >> $GITHUB_OUTPUT
else
echo "security_issues=false" >> $GITHUB_OUTPUT
fi
continue-on-error: true
- name: Save security findings comment
if: steps.secret-scan.outputs.security_issues == 'true'
uses: actions/github-script@v7
env:
SECURITY_ISSUES: ${{ steps.secret-scan.outputs.issues }}
with:
script: |
const fs = require('fs');
const path = require('path');
const dir = './security-warning';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir, { recursive: true });
}
const body = `## Security Scan Warning\n\nPotential security issues detected in this PR:\n${process.env.SECURITY_ISSUES}\n\nPlease review before merging. @knoxiboy`;
fs.writeFileSync(path.join(dir, 'security-warning.txt'), body);
- name: Upload security findings artifact
if: steps.secret-scan.outputs.security_issues == 'true'
uses: actions/upload-artifact@v4
with:
name: security-warning
path: security-warning/
if-no-files-found: ignore
# ─────────────────────────────────────────
# 5. PR quality gate — basic checks
# ─────────────────────────────────────────
pr-quality-gate:
name: PR Quality Gate
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check PR quality
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const pr = context.payload.pull_request;
const title = pr.title || '';
const body = pr.body || '';
const issues = [];
// 1. Title format check
const validPrefixes = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'perf', 'ci', 'build', 'revert'];
const hasValidPrefix = validPrefixes.some(p => title.toLowerCase().startsWith(p));
if (!hasValidPrefix) {
issues.push(`**Title format**: Title should start with a conventional commit prefix (e.g. \`feat:\`, \`fix:\`, \`docs:\`). Current: \`${title}\``);
}
// 2. PR description check
if (body.trim().length < 50) {
issues.push('**Description**: PR description is too short. Please describe what changes were made and why.');
}
// 3. Check for linked issue
const hasLinkedIssue = /closes?\s+#\d+|fixes?\s+#\d+|resolves?\s+#\d+/i.test(body);
if (!hasLinkedIssue) {
issues.push('**Linked Issue**: No linked issue found. Please add `Closes #<issue-number>` to your PR description.');
}
// 4. Check for test mention
const hasTestMention = /test|spec|jest|vitest|playwright/i.test(body);
if (!hasTestMention) {
issues.push('**Testing**: No mention of tests in the PR description. Please describe how you tested your changes.');
}
// Post results
if (issues.length > 0) {
const comment = `## PR Quality Check\n\nThe following items need attention:\n\n${issues.map(i => `- ${i}`).join('\n')}\n\n> These are suggestions to improve PR quality. The PR can still be merged after review.`;
const fs = require('fs');
const path = require('path');
const dir = './quality-gate-warning';
if (!fs.existsSync(dir)){
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(path.join(dir, 'quality-gate-warning.txt'), comment);
console.log('Saved quality gate feedback to file');
} else {
console.log('PR passed all quality checks');
}
- name: Upload quality gate warning artifact
uses: actions/upload-artifact@v4
with:
name: quality-gate-warning
path: quality-gate-warning/
if-no-files-found: ignore