Skip to content

EasyAudit - fix & PR (paid) #49

EasyAudit - fix & PR (paid)

EasyAudit - fix & PR (paid) #49

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