EasyAudit - fix & PR (paid) #49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "EasyAudit - fix & PR (paid)" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| ack_paid: | |
| description: "I confirm this action is PAID and a PR will be billed" | |
| required: true | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| fix-and-pr: | |
| if: ${{ inputs.ack_paid == true }} | |
| runs-on: ubuntu-latest | |
| container: | |
| image: ghcr.io/crealoz/easyaudit:latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Scan (JSON) | |
| run: | | |
| set -euo pipefail | |
| mkdir -p report | |
| # Run EasyAudit scan and produce JSON output | |
| easyaudit scan \ | |
| --format=json \ | |
| --output=report/easyaudit-report.json \ | |
| "$GITHUB_WORKSPACE" \ | |
| --exclude="vendor,generated,var,pub/static,pub/media" | |
| test -s report/easyaudit-report.json | |
| - name: Apply fixes (paid) + generate patch file | |
| id: fix | |
| env: | |
| EASYAUDIT_AUTH: ${{ secrets.EASYAUDIT_AUTH }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| # Build a safe patch name with branch name + timestamp | |
| BRANCH_NAME="${GITHUB_REF_NAME:-manual}" | |
| BRANCH_SAFE="$(printf '%s' "$BRANCH_NAME" | sed -E 's/[^a-zA-Z0-9._-]+/-/g')" | |
| TS="$(date +%Y%m%d-%H%M%S)" | |
| PATCH_NAME="patch-${BRANCH_SAFE}-${TS}" | |
| # Run fix-apply (produces individual patch files under patches/) | |
| easyaudit fix-apply report/easyaudit-report.json --confirm | |
| echo "patch_name=$PATCH_NAME" >> "$GITHUB_OUTPUT" | |
| - name: Build PR body | |
| run: | | |
| php -r ' | |
| $report = json_decode(file_get_contents("report/easyaudit-report.json"), true); | |
| $branch = getenv("GITHUB_REF_NAME") ?: "unknown"; | |
| $workspace = rtrim(getenv("GITHUB_WORKSPACE") ?: "", "/"); | |
| // Collect rule descriptions from report | |
| $ruleDefs = []; | |
| foreach ($report as $key => $finding) { | |
| if ($key === "metadata" || !isset($finding["ruleId"])) continue; | |
| $ruleDefs[$finding["ruleId"]] = $finding["shortDescription"] ?? $finding["name"] ?? $finding["ruleId"]; | |
| } | |
| // Parse patches: extract applied rules and file path per patch | |
| $fileRules = []; | |
| $ruleCounts = []; | |
| $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator("patches/", FilesystemIterator::SKIP_DOTS)); | |
| foreach ($it as $f) { | |
| if (!$f->isFile()) continue; | |
| $content = file_get_contents($f->getPathname()); | |
| preg_match("/^# Applied rules:\s*(.+)$/m", $content, $m); | |
| $rules = $m ? array_map("trim", explode(",", $m[1])) : []; | |
| preg_match("/^--- a\/.+?\/(.+)$/m", $content, $p); | |
| $path = $p[1] ?? basename($f->getPathname()); | |
| $path = str_replace($workspace . "/", "", $path); | |
| // Strip leading / from workspace-absolute paths | |
| $path = ltrim(str_replace("/" . ltrim($workspace, "/") . "/", "", "/" . $path), "/"); | |
| $fileRules[$path] = $rules; | |
| foreach ($rules as $r) { $ruleCounts[$r] = ($ruleCounts[$r] ?? 0) + 1; } | |
| } | |
| ksort($fileRules); | |
| ksort($ruleCounts); | |
| // Build markdown | |
| $md = "## Summary\n\n"; | |
| $md .= "EasyAudit automatically generated fixes from branch `$branch`.\n\n"; | |
| if ($ruleCounts) { | |
| $md .= "### Applied fixes\n\n"; | |
| $md .= "| Rule | Description | Files |\n"; | |
| $md .= "|------|-------------|-------|\n"; | |
| foreach ($ruleCounts as $rule => $count) { | |
| $desc = $ruleDefs[$rule] ?? ""; | |
| $md .= "| `$rule` | $desc | $count |\n"; | |
| } | |
| $md .= "\n"; | |
| } | |
| if ($fileRules) { | |
| $md .= "### Modified files\n\n"; | |
| foreach ($fileRules as $path => $rules) { | |
| $md .= "- `$path`" . ($rules ? " — " . implode(", ", $rules) : "") . "\n"; | |
| } | |
| } | |
| file_put_contents("pr-body.md", $md); | |
| echo $md; | |
| ' | |
| - name: Apply patches individually | |
| id: apply | |
| working-directory: ${{ github.workspace }} | |
| run: | | |
| set -eu | |
| git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| APPLIED=0 | |
| for PATCH in $(find patches/ -type f | sort); do | |
| echo "Applying: $PATCH" | |
| # Remove comment lines and normalize workspace paths (pipe to avoid sed -i issues in Alpine) | |
| grep -v '^# ' "$PATCH" \ | |
| | sed "s|a/$GITHUB_WORKSPACE/|a/|g; s|b/$GITHUB_WORKSPACE/|b/|g" \ | |
| > "$PATCH.clean" || true | |
| mv "$PATCH.clean" "$PATCH" | |
| head -n 3 "$PATCH" | |
| if git apply --index -p1 "$PATCH"; then | |
| APPLIED=$((APPLIED + 1)) | |
| else | |
| echo "Warning: failed to apply $PATCH" | |
| fi | |
| done | |
| echo "Applied $APPLIED patch(es)" | |
| if [ "$APPLIED" -eq 0 ]; then | |
| echo "No patches could be applied" | |
| exit 1 | |
| fi | |
| - name: Clean up generated artifacts | |
| id: cleanup | |
| run: | | |
| { | |
| echo 'pr_body<<EOF' | |
| cat pr-body.md | |
| echo 'EOF' | |
| } >> "$GITHUB_OUTPUT" | |
| rm -rf report/ patches/ pr-body.md | |
| - name: Create Pull Request | |
| uses: peter-evans/create-pull-request@v8 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| branch: ${{ github.ref_name }}-easyaudit-fix | |
| commit-message: "Apply EasyAudit fixes: ${{ steps.fix.outputs.patch_name }}" | |
| title: "EasyAudit automatic PR" | |
| body: ${{ steps.cleanup.outputs.pr_body }} | |
| signoff: false | |
| draft: false | |
| # delete-branch: true |