diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04a6547..4cf6a54 100755 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,134 +1,27 @@ -name: CI — Lint & Test +## +# Thin CI caller — peptide-news-plugin +# +# Delegates all lint/test/file-size jobs to the estate reusable workflow. +# Per estate standard: workflow_call is required so deploy.yml can gate on it. +# See: peptiderepo/peptide-e2e/.github/workflows/ci.yml@main for job definitions. +## +name: CI on: + pull_request: {} push: - branches: [ main ] - pull_request: - branches: [ main ] - workflow_call: + branches: [main] + workflow_call: {} +# Required: calling workflow must declare contents: write so the reusable +# phpcs job can commit phpcbf auto-fixes back to the PR branch. permissions: - contents: read + contents: write jobs: - # ── PHP Syntax Check ───────────────────────────────────────────── - lint-php: - name: PHP Lint (${{ matrix.php }}) - runs-on: ubuntu-latest - strategy: - matrix: - php: ['8.1', '8.2', '8.3'] - steps: - - uses: actions/checkout@v4 - - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - tools: composer - - - name: Syntax check all PHP files - run: find . -name '*.php' -not -path './vendor/*' -print0 | xargs -0 -n1 php -l - - # ── Security Audit ─────────────────────────────────────────────── - security-audit: - name: Security Audit - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Check for common PHP security issues - run: | - echo ":: Checking for direct SQL queries without prepare..." - # Exclude uninstall.php (DROP TABLE is standard WP pattern), activator (table DDL), - # and logger (TRUNCATE) — these use $wpdb->prefix which is safe internal state. - if grep -r "query\s*(\s*['\"].*\$" --include="*.php" --exclude-dir=vendor . 2>/dev/null \ - | grep -v "\\\$wpdb->prepare" \ - | grep -v "uninstall\.php" \ - | grep -v "class-peptide-news-activator\.php" \ - | grep -v "class-peptide-news-logger\.php" \ - | grep -v "DROP TABLE" \ - | grep -v "TRUNCATE" \ - && [ \${PIPESTATUS[0]} -eq 0 ]; then - echo "WARNING: Found potential unescaped SQL queries. Use wpdb->prepare() for all dynamic SQL." - exit 1 - fi - - echo ":: Checking for eval() usage..." - if grep -r "eval\s*(" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then - echo "ERROR: eval() found. This is a critical security risk." - exit 1 - fi - - echo ":: Checking for base64_decode without validation..." - if grep -r "base64_decode\s*(" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then - echo "WARNING: Found base64_decode(). Ensure the input is properly validated." - fi - - echo ":: Checking for file_get_contents with user input..." - if grep -r "file_get_contents\s*(\s*\$" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then - echo "WARNING: Found file_get_contents with variable. Ensure input is validated and restricted." - fi - - echo "All security checks passed." - - # ── PHPCS Coding Standards ─────────────────────────────────────── - phpcs: - name: PHPCS - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - tools: composer - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: Run PHPCS - run: vendor/bin/phpcs --standard=.phpcs.xml.dist - continue-on-error: true - - # ── PHPUnit Tests ──────────────────────────────────────────────── - phpunit: - name: PHPUnit (${{ matrix.php }}) - runs-on: ubuntu-latest - strategy: - matrix: - php: ['8.1', '8.2', '8.3'] - steps: - - uses: actions/checkout@v4 - - - name: Set up PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - tools: composer - coverage: xdebug - - - name: Install dependencies - run: composer install --prefer-dist --no-progress - - - name: Run PHPUnit - run: vendor/bin/phpunit --testdox - - # ── JavaScript Lint ────────────────────────────────────────────── - lint-js: - name: JS Lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up Node - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Check JS syntax - run: | - for f in $(find . -name '*.js' -not -path './vendor/*' -not -path './node_modules/*' -not -path '*/vendor/*'); do - node --check "$f" || exit 1 - done + ci: + uses: peptiderepo/peptide-e2e/.github/workflows/ci.yml@main + with: + tests: stubs + has_js: true + secrets: inherit diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b2e104a..9b1233e 100755 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -4,8 +4,12 @@ on: push: branches: [ main ] +# contents: write required so the ci.yml caller can pass write permission +# through to the phpcbf auto-commit step in the reusable workflow. +# (phpcbf commit only fires on pull_request events, but GH enforces caller +# permissions at token-grant time, not at step-execution time.) permissions: - contents: read + contents: write concurrency: group: deploy-peptide-news-plugin diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml new file mode 100644 index 0000000..428411a --- /dev/null +++ b/.github/workflows/security-audit.yml @@ -0,0 +1,58 @@ +## +# Security audit — peptide-news-plugin +# +# Standalone workflow kept separate from the estate CI caller so it can evolve +# independently and run on every PR without being bundled into the reusable pipeline. +# Checks for: unescaped SQL, eval(), base64_decode(), file_get_contents with user input. +## +name: Security Audit + +on: + pull_request: {} + push: + branches: [main] + +permissions: + contents: read + +jobs: + security-audit: + name: Security Audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for common PHP security issues + run: | + echo ":: Checking for direct SQL queries without prepare..." + # Exclude uninstall.php (DROP TABLE is standard WP pattern), activator (table DDL), + # and logger (TRUNCATE) — these use $wpdb->prefix which is safe internal state. + if grep -r "query\s*(\s*['\"].*\$" --include="*.php" --exclude-dir=vendor . 2>/dev/null \ + | grep -v "\$wpdb->prepare" \ + | grep -v "uninstall\.php" \ + | grep -v "class-peptide-news-activator\.php" \ + | grep -v "class-peptide-news-logger\.php" \ + | grep -v "DROP TABLE" \ + | grep -v "TRUNCATE" \ + && [ ${PIPESTATUS[0]} -eq 0 ]; then + echo "WARNING: Found potential unescaped SQL queries. Use wpdb->prepare() for all dynamic SQL." + exit 1 + fi + + echo ":: Checking for eval() usage..." + if grep -r "eval\s*(" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then + echo "ERROR: eval() found. This is a critical security risk." + exit 1 + fi + + echo ":: Checking for base64_decode without validation..." + if grep -r "base64_decode\s*(" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then + echo "WARNING: Found base64_decode(). Ensure the input is properly validated." + fi + + echo ":: Checking for file_get_contents with user input..." + if grep -r "file_get_contents\s*(\s*\$" --include="*.php" --exclude-dir=vendor . 2>/dev/null; then + echo "WARNING: Found file_get_contents with variable. Ensure input is validated and restricted." + fi + + echo "All security checks passed." diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ba2b9af --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +All notable changes to Peptide News Plugin are documented here. +Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +Versioning: [Semantic Versioning](https://semver.org/). + +## [2.5.0] — 2026-06-16 + +### Changed +- **CI standardization (estate wave 2):** Replace per-repo CI jobs in + `ci.yml` with a thin caller of `peptiderepo/peptide-e2e/.github/workflows/ci.yml@main` + (`tests: stubs`, `has_js: true`). Adds `workflow_call` trigger so `deploy.yml` + gate remains valid. +- Extract `security-audit` job from `ci.yml` into standalone + `.github/workflows/security-audit.yml` (kept as-is, unique to this repo). +- `deploy.yml`: elevate permissions to `contents: write` so the nested + phpcbf commit-back step in the reusable workflow receives the correct token scope. +- `composer.json`: pin `test` script to `vendor/bin/phpunit --configuration phpunit.xml.dist` + for explicit path resolution in CI; pin `lint` / `lint:fix` to `vendor/bin/`. +- `phpunit.xml.dist`: add XSD reference for PHPUnit 9.6; drop deprecated + `convertErrorsToExceptions`, `convertNoticesToExceptions`, `convertWarningsToExceptions` + attributes. + +### Notes +- `rollback.yml` and `cto-review.yml` and `main-push-audit.yml` unchanged — unique / estate-separate. +- No functional code changes in this commit. + +## Prior history + +Versions prior to 2.5.0 were not tracked in a CHANGELOG. See git log for details. diff --git a/composer.json b/composer.json index eb532a1..d519518 100755 --- a/composer.json +++ b/composer.json @@ -21,9 +21,9 @@ } }, "scripts": { - "test": "phpunit", - "lint": "phpcs", - "lint:fix": "phpcbf", + "test": "vendor/bin/phpunit --configuration phpunit.xml.dist", + "lint": "vendor/bin/phpcs", + "lint:fix": "vendor/bin/phpcbf", "check": [ "@lint", "@test" diff --git a/peptide-news-plugin.php b/peptide-news-plugin.php index a9817cc..dfe77bd 100755 --- a/peptide-news-plugin.php +++ b/peptide-news-plugin.php @@ -3,7 +3,7 @@ * Plugin Name: Peptide News Aggregator * Plugin URI: https://github.com/peptiderepo/peptide-news-plugin * Description: Aggregates and displays the latest peptide research news from multiple sources with click analytics and trend reporting. - * Version: 2.4.1 + * Version: 2.5.0 * Author: peptiderepo * Author URI: https://github.com/peptiderepo * License: GPL-2.0+ @@ -24,7 +24,7 @@ if ( ! defined( 'WPINC' ) ) { /** * Current plugin version — follows SemVer. */ -define( 'PEPTIDE_NEWS_VERSION', '2.4.0' ); +define( 'PEPTIDE_NEWS_VERSION', '2.5.0' ); define( 'PEPTIDE_NEWS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'PEPTIDE_NEWS_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'PEPTIDE_NEWS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 56d13db..62a2b11 100755 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,11 +1,10 @@