Skip to content

Commit 9fb6293

Browse files
committed
Merge remote-tracking branch 'origin/develop' into codex/run-automated-bug-detection-cycle
2 parents 908597c + a0d53e4 commit 9fb6293

588 files changed

Lines changed: 105538 additions & 157820 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.babelrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"presets": [
3+
"@babel/preset-env",
4+
[
5+
"@babel/preset-react",
6+
{
7+
"runtime": "automatic"
8+
}
9+
]
10+
]
11+
}

.coderabbit.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
reviews:
2+
branches:
3+
include:
4+
- main
5+
- develop
6+
- release/**

.eslintrc

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,28 @@
33
"env": {
44
"browser": true,
55
"node": false,
6-
"jest": true,
6+
"jest": true
77
},
88
"globals": {
99
"wp": true,
1010
"jQuery": true,
1111
"edac_script_vars": true,
1212
"ajaxurl": true
13-
}
13+
},
14+
"overrides": [
15+
{
16+
"files": [ "src/sidebar/**/*.js", "src/sidebar/**/*.jsx", "src/issueModal/**/*.js", "src/issueModal/**/*.jsx" ],
17+
"plugins": [ "react" ],
18+
"parserOptions": {
19+
"ecmaVersion": 2021,
20+
"sourceType": "module",
21+
"ecmaFeatures": {
22+
"jsx": true
23+
}
24+
},
25+
"rules": {
26+
"react/jsx-uses-vars": "error"
27+
}
28+
}
29+
]
1430
}

.github/agents/bug-hunter.yml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
name: bug-hunter
2+
description: Automated bug finder and fixer for Accessibility Checker plugin
3+
instructions: |
4+
You are a specialized bug hunter for the Accessibility Checker WordPress plugin.
5+
6+
## CRITICAL: Avoid Duplicate Work
7+
8+
**ALWAYS check the task context for**:
9+
- Files already being fixed in open PRs - SKIP these completely
10+
- Bug types already identified - DO NOT create duplicate fixes
11+
- Recently changed files - PRIORITIZE these for analysis
12+
13+
**Before creating ANY PR**:
14+
1. Verify the bug is NOT mentioned in existing open PRs
15+
2. Verify the files you're changing are NOT in open PRs
16+
3. Only create a PR if you found a NEW, DISTINCT bug
17+
18+
## Analysis Focus
19+
- Scan PHP files for WordPress plugin bugs (security, logic, performance)
20+
- Check for WPCS compliance issues that could cause bugs
21+
- Find undefined variables, incorrect hook usage
22+
- Spot database query issues or SQL injection vulnerabilities
23+
- Check for missing nonce verification or capability checks
24+
- **SKIP any files listed in the "Files already in open PRs" context**
25+
26+
## Bug Severity Priority (fix in this order)
27+
28+
**CRITICAL** (fix immediately):
29+
- SQL injection vulnerabilities
30+
- XSS vulnerabilities (unsanitized output)
31+
- Authentication bypass
32+
- Privilege escalation
33+
- Arbitrary file upload
34+
- Remote code execution
35+
- Fatal PHP errors (application crashes)
36+
37+
**HIGH** (fix if no critical):
38+
- CSRF vulnerabilities (missing nonces)
39+
- Missing capability checks
40+
- Path traversal vulnerabilities
41+
- Input validation failures leading to security issues
42+
- Unhandled exceptions that could expose sensitive data
43+
44+
**MEDIUM** (fix if no high):
45+
- Logic errors causing incorrect behavior
46+
- PHP warnings (deprecated functions, undefined variables, etc.)
47+
- Performance issues (N+1 queries, inefficient loops)
48+
- Memory leaks
49+
- Deprecated function usage
50+
- Incorrect hook usage
51+
- Type mismatches that don't cause errors yet
52+
53+
**LOW** (fix only if nothing else):
54+
- Code style inconsistencies that could lead to bugs
55+
- Missing type hints that could prevent future errors
56+
- Unclear variable names causing confusion
57+
- PHP notices (less severe than warnings)
58+
59+
## Coding Standards
60+
- Follow WordPress coding standards (WPCS)
61+
- Use EqualizeDigital\AccessibilityChecker namespace for class files
62+
- Use `edac_` prefix ONLY for functions in global namespace (hooks, template functions)
63+
- Avoid adding new global functions - prefer namespaced classes
64+
- PHP 7.4+ compatibility
65+
- Security best practices (sanitization, validation, nonces)
66+
67+
## Fix Approach
68+
- Fix ONLY ONE bug per run (even if you find multiple)
69+
- Make minimal, focused changes
70+
- Add PHPUnit tests for the bug fix:
71+
* Create test in tests/phpunit/ directory
72+
* Name test class matching the fixed file (e.g., AdminTest.php)
73+
* Include a test that reproduces the bug (demonstrates the issue)
74+
* Include a test that verifies the fix works
75+
* Follow WordPress test framework patterns
76+
- **RUN the tests to verify they pass**:
77+
* Execute `npm run test:php`
78+
* Ensure the bug reproduction test fails before the fix
79+
* Ensure all tests pass after the fix
80+
* Fix any test failures before creating PR
81+
- Use branch name: `copilot/automated-bug-fix/{short-description-of-bug-fixed}`
82+
- **Only create PR if all tests pass**
83+
84+
## Test-Driven Bug Fix Workflow
85+
1. **Write failing test** - Create test that reproduces the bug (should fail)
86+
2. **Verify test fails** - Run tests to confirm the bug is caught
87+
3. **Implement fix** - Make minimal code changes to fix the bug
88+
4. **Run all tests** - Execute full test suite to verify fix works
89+
5. **Check for regressions** - Ensure no existing tests broke
90+
6. **Create DRAFT PR** - Only if all tests pass successfully
91+
92+
## PR Creation
93+
- **Always create as DRAFT** - PRs should be drafts initially for human review
94+
- Add label `automated-bug-fix` (workflow will add this)
95+
- Include clear description of bug and fix
96+
- Reference any related issues if applicable
97+
- Human reviewers can mark as "Ready for review" after validation
98+
99+
## What NOT to Fix
100+
- Don't refactor working code without a bug
101+
- Don't change code style without fixing a bug
102+
- Don't add new features (this is bug fixing only)
103+
- Don't modify third-party dependencies
104+
- Don't change database schema
105+
- Don't update documentation only (unless it causes bugs)
106+
- Don't fix bugs in files already being modified in open PRs
107+
108+
## When to Exit Without PR
109+
- All found bugs are already in open PRs
110+
- The files with bugs are already being modified in open PRs
111+
- No bugs found in recently changed files
112+
- Unable to verify the bug is new/distinct
113+
114+
Only create a PR if you find a **legitimate, NEW bug** not covered by existing PRs.

.github/workflows/backport-to-develop.yml

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,38 +25,48 @@ jobs:
2525

2626
- name: Get merged branch name
2727
id: get-branch
28+
env:
29+
BRANCH_NAME: ${{ github.event.pull_request.head.ref }}
30+
HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
2831
run: |
29-
# Get the head branch name from the merged PR
30-
BRANCH_NAME="${{ github.event.pull_request.head.ref }}"
32+
# Get the head branch name and repo from the merged PR
3133
echo "branch-name=$BRANCH_NAME" >> $GITHUB_OUTPUT
32-
echo "Merged branch: $BRANCH_NAME"
34+
echo "head-repo=$HEAD_REPO" >> $GITHUB_OUTPUT
35+
echo "Merged branch: $BRANCH_NAME from $HEAD_REPO"
3336
3437
- name: Check if branch exists
3538
id: check-branch
39+
env:
40+
HEAD_REF: ${{ steps.get-branch.outputs.branch-name }}
41+
HEAD_REPO: ${{ steps.get-branch.outputs.head-repo }}
3642
run: |
37-
BRANCH_NAME="${{ steps.get-branch.outputs.branch-name }}"
38-
39-
# Check if the branch still exists on the remote
40-
if git ls-remote --heads origin "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then
43+
# Check if the branch still exists on the fork remote
44+
if git ls-remote "https://github.com/${HEAD_REPO}.git" "refs/heads/${HEAD_REF}" | grep -q "refs/heads/${HEAD_REF}"; then
4145
echo "branch-exists=true" >> $GITHUB_OUTPUT
42-
echo "Branch $BRANCH_NAME exists and can be used for backport"
46+
echo "Branch $HEAD_REF exists in $HEAD_REPO and can be used for backport"
4347
else
4448
echo "branch-exists=false" >> $GITHUB_OUTPUT
45-
echo "Branch $BRANCH_NAME no longer exists, cannot create backport PR"
49+
echo "Branch $HEAD_REF no longer exists in $HEAD_REPO, cannot create backport PR"
4650
fi
4751
4852
- name: Create backport PR
4953
if: steps.check-branch.outputs.branch-exists == 'true'
5054
uses: actions/github-script@v7
55+
env:
56+
BRANCH_NAME: ${{ steps.get-branch.outputs.branch-name }}
57+
ORIGINAL_PR_NUMBER: ${{ github.event.pull_request.number }}
58+
ORIGINAL_PR_TITLE: ${{ github.event.pull_request.title }}
59+
ORIGINAL_PR_BODY: ${{ github.event.pull_request.body }}
60+
ORIGINAL_PR_AUTHOR: ${{ github.event.pull_request.user.login }}
5161
with:
5262
github-token: ${{ secrets.GITHUB_TOKEN }}
5363
script: |
54-
const branchName = '${{ steps.get-branch.outputs.branch-name }}';
55-
const originalPrNumber = context.payload.pull_request.number;
56-
const originalPrTitle = context.payload.pull_request.title;
57-
const originalPrBody = context.payload.pull_request.body || '';
58-
const originalPrAuthor = context.payload.pull_request.user.login;
59-
64+
const branchName = process.env.BRANCH_NAME;
65+
const originalPrNumber = process.env.ORIGINAL_PR_NUMBER;
66+
const originalPrTitle = process.env.ORIGINAL_PR_TITLE;
67+
const originalPrBody = process.env.ORIGINAL_PR_BODY || '';
68+
const originalPrAuthor = process.env.ORIGINAL_PR_AUTHOR;
69+
6070
// Create the backport PR
6171
try {
6272
const response = await github.rest.pulls.create({

.github/workflows/build-plugin-with-ref.yml

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,57 @@ jobs:
253253
path: ${{ env.REF_ZIP_FOLDER }}
254254
if-no-files-found: error
255255

256+
- name: Resolve public plugin URLs for Playground
257+
id: playground-zips
258+
if: github.event.repository.private == false
259+
run: |
260+
PRIMARY_PLUGIN_ZIP_URL=""
261+
REF_PLUGIN_ZIP_URL=""
262+
263+
if [ -n "${PRIMARY_ZIP_NAME:-}" ]; then
264+
if [ "${{ github.event_name }}" = "release" ]; then
265+
PRIMARY_PLUGIN_ZIP_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ github.event.release.tag_name }}/${PRIMARY_ZIP_NAME}"
266+
else
267+
PRIMARY_PLUGIN_ZIP_URL="https://nightly.link/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/${PRIMARY_ZIP_NAME_NO_EXT}.zip"
268+
fi
269+
fi
270+
271+
if [ "${{ steps.check_ref.outputs.need_ref_build }}" = "true" ] && [ -n "${REF_ZIP_NAME:-}" ]; then
272+
if [ "${{ github.event_name }}" = "release" ]; then
273+
REF_PLUGIN_ZIP_URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ github.event.release.tag_name }}/${REF_ZIP_NAME}"
274+
else
275+
REF_PLUGIN_ZIP_URL="https://nightly.link/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/${REF_ZIP_NAME_NO_EXT}.zip"
276+
fi
277+
fi
278+
279+
echo "primary_plugin_zip_url=$PRIMARY_PLUGIN_ZIP_URL" >> "$GITHUB_OUTPUT"
280+
echo "ref_plugin_zip_url=$REF_PLUGIN_ZIP_URL" >> "$GITHUB_OUTPUT"
281+
282+
- name: Build WordPress Playground links
283+
if: github.event.repository.private == false
284+
run: |
285+
export PRIMARY_PLUGIN_ZIP_URL='${{ steps.playground-zips.outputs.primary_plugin_zip_url }}'
286+
export REF_PLUGIN_ZIP_URL='${{ steps.playground-zips.outputs.ref_plugin_zip_url }}'
287+
288+
build_playground_url() {
289+
local plugin_url="$1"
290+
python3 -c 'import base64,json,sys,urllib.parse; plugin_url=sys.argv[1]; blueprint={"landingPage":"/wp-admin/plugins.php","steps":[{"step":"login"},{"step":"installPlugin","pluginZipFile":{"resource":"url","url":plugin_url}},{"step":"activatePlugin","pluginPath":"accessibility-checker/accessibility-checker.php"}]}; blueprint_json=json.dumps(blueprint,separators=(",",":")); data_uri="data:application/json;base64,"+base64.b64encode(blueprint_json.encode("utf-8")).decode("ascii"); encoded_blueprint_url=urllib.parse.quote(data_uri,safe=""); print(f"https://playground.wordpress.net/?blueprint-url={encoded_blueprint_url}")' "$plugin_url"
291+
}
292+
293+
PRIMARY_PLAYGROUND_URL=""
294+
REF_PLAYGROUND_URL=""
295+
296+
if [ -n "$PRIMARY_PLUGIN_ZIP_URL" ]; then
297+
PRIMARY_PLAYGROUND_URL="$(build_playground_url "$PRIMARY_PLUGIN_ZIP_URL")"
298+
fi
299+
300+
if [ -n "$REF_PLUGIN_ZIP_URL" ]; then
301+
REF_PLAYGROUND_URL="$(build_playground_url "$REF_PLUGIN_ZIP_URL")"
302+
fi
303+
304+
echo "PRIMARY_PLAYGROUND_URL=$PRIMARY_PLAYGROUND_URL" >> "$GITHUB_ENV"
305+
echo "REF_PLAYGROUND_URL=$REF_PLAYGROUND_URL" >> "$GITHUB_ENV"
306+
256307
- name: Upload to release (both zips)
257308
if: github.event_name == 'release'
258309
uses: softprops/action-gh-release@v2
@@ -286,7 +337,17 @@ jobs:
286337
? `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${runId}/artifacts/${artifact.id}`
287338
: runUrl;
288339
289-
const body = `✅ Accessibility Checker build (primary only)\n\n- **Artifact**: [Download ${primaryName}.zip](${downloadUrl})\n- **Workflow run**: [View logs](${runUrl})`;
340+
const primaryPlaygroundUrl = process.env.PRIMARY_PLAYGROUND_URL;
341+
const primaryPlaygroundLine = primaryPlaygroundUrl
342+
? `\n- **Playground (primary)**: [Open with plugin preinstalled](${primaryPlaygroundUrl})`
343+
: `\n- **Playground (primary)**: Not available for this run (repository may be private or plugin ZIP URL is not publicly accessible).`;
344+
345+
const refPlaygroundUrl = process.env.REF_PLAYGROUND_URL;
346+
const refPlaygroundLine = refPlaygroundUrl
347+
? `\n- **Playground (ref)**: [Open with plugin preinstalled](${refPlaygroundUrl})`
348+
: '';
349+
350+
const body = `✅ Accessibility Checker build (primary only)\n\n- **Artifact**: [Download ${primaryName}.zip](${downloadUrl})\n- **Workflow run**: [View logs](${runUrl})${primaryPlaygroundLine}${refPlaygroundLine}`;
290351
await github.rest.issues.createComment({
291352
owner: context.repo.owner,
292353
repo: context.repo.repo,
@@ -319,10 +380,21 @@ jobs:
319380
echo "=== Build Summary ==="
320381
echo "Mode: ${{ steps.setref.outputs.mode }}"
321382
echo "Primary zip (empty ref): ${{ env.PRIMARY_ZIP_PATH }}"
383+
if [ -n "${PRIMARY_PLAYGROUND_URL:-}" ]; then
384+
echo "Playground (primary): ${PRIMARY_PLAYGROUND_URL}"
385+
else
386+
echo "Playground (primary): skipped (repo is private or URL unavailable)"
387+
fi
322388
if [ "${{ steps.check_ref.outputs.need_ref_build }}" = "true" ]; then
323389
echo "Ref zip (ref=${{ steps.setref.outputs.ref_param }}): ${{ env.REF_ZIP_PATH }}"
390+
if [ -n "${REF_PLAYGROUND_URL:-}" ]; then
391+
echo "Playground (ref): ${REF_PLAYGROUND_URL}"
392+
else
393+
echo "Playground (ref): skipped (repo is private or URL unavailable)"
394+
fi
324395
else
325396
echo "Ref zip: Not built"
397+
echo "Playground (ref): Not built"
326398
fi
327399
if [ "${{ github.event_name }}" = "release" ]; then
328400
echo "Uploaded to release: ${{ github.event.release.html_url }}"

0 commit comments

Comments
 (0)