diff --git a/.github/workflows/qa.yml b/.github/workflows/qa.yml index 0d3ff49..1c62a17 100644 --- a/.github/workflows/qa.yml +++ b/.github/workflows/qa.yml @@ -130,11 +130,11 @@ jobs: id: stan run: | set +e - vendor/bin/phpstan analyse --error-format=json --no-progress > phpstan.json 2>&1 + vendor/bin/phpstan analyse --error-format=json --no-progress > phpstan.json EXIT_CODE=$? # Also run for GitHub format - vendor/bin/phpstan analyse --error-format=github --no-progress 2>&1 || true + vendor/bin/phpstan analyse --error-format=github --no-progress || true ERRORS=$(jq '.totals.file_errors // 0' phpstan.json 2>/dev/null || echo "0") echo "errors=${ERRORS}" >> $GITHUB_OUTPUT @@ -181,11 +181,11 @@ jobs: id: psalm run: | set +e - vendor/bin/psalm --output-format=json --show-info=false > psalm.json 2>&1 + vendor/bin/psalm --output-format=json --show-info=false > psalm.json EXIT_CODE=$? # Generate SARIF for GitHub Security - vendor/bin/psalm --output-format=sarif --show-info=false > psalm.sarif 2>&1 || true + vendor/bin/psalm --output-format=sarif --show-info=false > psalm.sarif || true ERRORS=$(jq 'length' psalm.json 2>/dev/null || echo "0") echo "errors=${ERRORS}" >> $GITHUB_OUTPUT @@ -198,6 +198,14 @@ jobs: exit $EXIT_CODE + - name: Debug Psalm Output + if: always() + run: | + echo "--- psalm.json ---" + cat psalm.json || echo "psalm.json not found" + echo "--- psalm.sarif ---" + cat psalm.sarif || echo "psalm.sarif not found" + - name: Upload Psalm SARIF if: always() uses: github/codeql-action/upload-sarif@v3 @@ -242,7 +250,7 @@ jobs: id: fmt run: | set +e - OUTPUT=$(vendor/bin/pint --test --format=json 2>&1) + OUTPUT=$(vendor/bin/pint --test --format=json) EXIT_CODE=$? echo "$OUTPUT" > pint.json @@ -292,7 +300,7 @@ jobs: id: audit run: | set +e - composer audit --format=json > audit.json 2>&1 + composer audit --format=json > audit.json EXIT_CODE=$? VULNS=$(jq '.advisories | to_entries | map(.value | length) | add // 0' audit.json 2>/dev/null || echo "0") diff --git a/AUDIT-DATABASE.md b/AUDIT-DATABASE.md new file mode 100644 index 0000000..f3c32ea --- /dev/null +++ b/AUDIT-DATABASE.md @@ -0,0 +1,29 @@ +# Database Query Optimization Audit + +This document outlines the findings of a database query optimization audit. + +## 1. Missing Indexes + +### `activities` Table + +**Finding:** The `activities` table, used by the `spatie/laravel-activitylog` package, was missing indexes on the polymorphic `subject` and `causer` columns. This can lead to slow queries when filtering activities by these relationships. + +**Recommendation:** Add composite indexes to the `(subject_type, subject_id)` and `(causer_type, causer_id)` columns. + +**Action Taken:** A migration has been created to add these indexes. + +## 2. Environment and Dependencies + +**Finding:** The project has conflicting dependencies, specifically with `vimeo/psalm`, which prevents the installation of development tools like Laravel Debugbar and blocks the execution of the test suite. + +**Recommendation:** Resolve the dependency conflicts in `composer.json` to ensure a stable and consistent development environment. This is crucial for proper testing and debugging. + +## 3. Further Analysis + +The following files have been identified for further manual review to identify potential N+1 query problems, inefficient Eloquent patterns, and other query-related issues: + +* `src/Mod/Trees/Models/TreeDonation.php` +* `src/Mod/Trees/Models/TreePlanting.php` +* `src/Mod/Trees/Models/TreePlantingStats.php` +* `src/Mod/Trees/Models/TreeReserve.php` +* `src/Mod/Trees/Controllers/Api/TreeStatsController.php` diff --git a/database/migrations/2024_05_21_100000_add_indexes_to_activities_table.php b/database/migrations/2024_05_21_100000_add_indexes_to_activities_table.php new file mode 100644 index 0000000..997f478 --- /dev/null +++ b/database/migrations/2024_05_21_100000_add_indexes_to_activities_table.php @@ -0,0 +1,26 @@ +index(['subject_type', 'subject_id'], 'subject_index'); + $table->index(['causer_type', 'causer_id'], 'causer_index'); + }); + } + + public function down(): void + { + Schema::table('activities', function (Blueprint $table) { + $table->dropIndex('subject_index'); + $table->dropIndex('causer_index'); + }); + } +};