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
6 changes: 6 additions & 0 deletions .changelog/composer-normalization-workflow-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: added
type: minor
---

Check this repository's root Composer metadata in CI and expose an opt-in `normalize-composer` boolean in the reusable check workflow. Reuse the reviewed installed tool in check mode, independent of changed PHP selection, without applying changes, maintaining locks or installing consumer packages.
6 changes: 6 additions & 0 deletions .changelog/trusted-consumer-runner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: added
type: minor
---

Allow same-repository data-only pull request checks to select existing Linux self-hosted runners through the reusable runs-on JSON input. Retain hosted defaults and route forks, executable ECS config and Rector to hosted Ubuntu before scheduling; validate the actual platform and execution boundary again before checkout.
17 changes: 16 additions & 1 deletion .github/workflows/code-standards-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ name: 'Internal: Optional PHP Analysis'
on:
workflow_call:
inputs:
runs-on:
default: '["ubuntu-latest"]'
type: string
php-version:
default: '8.3'
type: string
Expand All @@ -24,19 +27,31 @@ permissions:
contents: read
jobs:
analyze:
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && !inputs.rector && startsWith(toJSON(fromJSON(inputs.runs-on)), '[') && contains(fromJSON(inputs.runs-on), 'self-hosted') && contains(fromJSON(inputs.runs-on), 'Linux') && inputs.runs-on || '["ubuntu-latest"]') }}
timeout-minutes: 15
steps:
- name: Reject privileged events and invalid refs
id: runtime
shell: bash
env:
STANDARDS_RUNNER_OS: ${{ runner.os }}
STANDARDS_RECTOR_ENABLED: ${{ inputs.rector }}
STANDARDS_RUNNER_ENVIRONMENT: ${{ runner.environment }}
STANDARDS_HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
STANDARDS_REPOSITORY: ${{ github.repository }}
STANDARDS_EVENT: ${{ github.event_name }}
STANDARDS_JOB_JSON: ${{ toJSON(job) }}
STANDARDS_BASE: ${{ github.event.pull_request.base.sha }}
STANDARDS_HEAD: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
[[ "$STANDARDS_EVENT" == pull_request ]] || exit 1
[[ "$STANDARDS_RUNNER_OS" == Linux ]] || exit 1
[[ "$STANDARDS_RUNNER_ENVIRONMENT" == github-hosted || "$STANDARDS_RUNNER_ENVIRONMENT" == self-hosted ]] || exit 1
if [[ "$STANDARDS_RUNNER_ENVIRONMENT" == self-hosted ]]; then
[[ -n "$STANDARDS_REPOSITORY" && "$STANDARDS_HEAD_REPOSITORY" == "$STANDARDS_REPOSITORY" ]] || exit 1
[[ "$STANDARDS_RECTOR_ENABLED" == false ]] || exit 1
fi
[[ "$STANDARDS_BASE" =~ ^[a-fA-F0-9]{40}$ ]] || exit 1
[[ "$STANDARDS_HEAD" =~ ^[a-fA-F0-9]{40}$ ]] || exit 1
runtime=$(jq --slurp --raw-output --exit-status '
Expand Down
28 changes: 27 additions & 1 deletion .github/workflows/code-standards-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,48 @@ name: 'Internal: Check Changed PHP'
on:
workflow_call:
inputs:
runs-on:
default: '["ubuntu-latest"]'
type: string
php-version:
default: '8.3'
type: string
normalize-composer:
description: Explicitly check root Composer metadata without writing or updating locks.
default: false
type: boolean
config:
default: ''
type: string
permissions:
contents: read
jobs:
check:
runs-on: ubuntu-latest
runs-on: ${{ fromJSON(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && inputs.config == '' && startsWith(toJSON(fromJSON(inputs.runs-on)), '[') && contains(fromJSON(inputs.runs-on), 'self-hosted') && contains(fromJSON(inputs.runs-on), 'Linux') && inputs.runs-on || '["ubuntu-latest"]') }}
timeout-minutes: 15
steps:
- name: Reject privileged events and invalid refs
id: runtime
shell: bash
env:
STANDARDS_RUNNER_OS: ${{ runner.os }}
STANDARDS_EXECUTABLE_CONFIG: ${{ inputs.config }}
STANDARDS_RUNNER_ENVIRONMENT: ${{ runner.environment }}
STANDARDS_HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name }}
STANDARDS_REPOSITORY: ${{ github.repository }}
STANDARDS_EVENT: ${{ github.event_name }}
STANDARDS_JOB_JSON: ${{ toJSON(job) }}
STANDARDS_BASE: ${{ github.event.pull_request.base.sha }}
STANDARDS_HEAD: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
[[ "$STANDARDS_EVENT" == pull_request ]] || exit 1
[[ "$STANDARDS_RUNNER_OS" == Linux ]] || exit 1
[[ "$STANDARDS_RUNNER_ENVIRONMENT" == github-hosted || "$STANDARDS_RUNNER_ENVIRONMENT" == self-hosted ]] || exit 1
if [[ "$STANDARDS_RUNNER_ENVIRONMENT" == self-hosted ]]; then
[[ -n "$STANDARDS_REPOSITORY" && "$STANDARDS_HEAD_REPOSITORY" == "$STANDARDS_REPOSITORY" ]] || exit 1
[[ -z "$STANDARDS_EXECUTABLE_CONFIG" ]] || exit 1
fi
[[ "$STANDARDS_BASE" =~ ^[a-fA-F0-9]{40}$ ]] || exit 1
[[ "$STANDARDS_HEAD" =~ ^[a-fA-F0-9]{40}$ ]] || exit 1
runtime=$(jq --slurp --raw-output --exit-status '
Expand Down Expand Up @@ -75,3 +94,10 @@ jobs:
base-sha: ${{ github.event.pull_request.base.sha }}
head-sha: ${{ github.event.pull_request.head.sha }}
config: ${{ inputs.config }}
- name: Check Composer normalization
if: inputs.normalize-composer
env:
STANDARDS_ROOT: ${{ github.workspace }}/tool
STANDARDS_DIRECTORY: ${{ github.workspace }}/consumer
run: |
php "$STANDARDS_ROOT/bin/code-standards" normalize-composer "--directory=$STANDARDS_DIRECTORY"
11 changes: 11 additions & 0 deletions .github/workflows/code-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ name: 'Reusable: Code Standards'
on:
workflow_call:
inputs:
runs-on:
description: JSON Linux self-hosted labels for data-only same-repository PR checks; executable config, Rector and forks use hosted Ubuntu.
default: '["ubuntu-latest"]'
type: string
php-version:
description: Tool runtime PHP, at least 8.3; also used for syntax parsing.
default: '8.3'
type: string
normalize-composer:
description: Explicitly check root Composer metadata without writing or updating locks.
default: false
type: boolean
config:
description: Optional consumer-relative ECS config.
default: ''
Expand Down Expand Up @@ -37,13 +45,16 @@ jobs:
contents: read
uses: ./.github/workflows/code-standards-check.yml
with:
runs-on: ${{ inputs.runs-on }}
php-version: ${{ inputs.php-version }}
config: ${{ inputs.config }}
normalize-composer: ${{ inputs.normalize-composer }}
optional-analysis:
permissions:
contents: read
uses: ./.github/workflows/code-standards-analysis.yml
with:
runs-on: ${{ inputs.runs-on }}
php-version: ${{ inputs.php-version }}
magic-numbers: ${{ inputs.magic-numbers }}
magic-numbers-policy: ${{ inputs.magic-numbers-policy }}
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/repository-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ jobs:
COMPOSER_HOME: ${{ runner.temp }}/standards-composer-home
COMPOSER_CACHE_DIR: ${{ runner.temp }}/standards-composer-cache
- run: composer validate --strict
- name: Check Composer normalization
env:
STANDARDS_ROOT: ${{ github.workspace }}
STANDARDS_DIRECTORY: ${{ github.workspace }}
run: |
php "$STANDARDS_ROOT/bin/code-standards" normalize-composer "--directory=$STANDARDS_DIRECTORY"
- run: composer check
- name: Provision isolated Twig evaluation dependencies
run: composer install --working-dir=tests/Evaluation/Twig --no-dev --no-plugins --no-scripts --no-interaction --prefer-dist --no-progress
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/repository-pr-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ jobs:
reusable-check:
uses: ./.github/workflows/code-standards.yml
with:
normalize-composer: true
magic-numbers: true
magic-numbers-policy: report
8 changes: 6 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ reusables under `.github/workflows/code-standards*.yml`, own event workflows use
Future semantic work requires an explicit consumer target PHP and opt-in.
- PR checks use `pull_request`, exact head/base, merge-base comparison and Git's
NUL-delimited protocol. Never run untrusted PHP on privileged target events or
self-hosted runners. No secrets are accepted by the checking reusable.
self-hosted runners. Custom consumer runners require Linux and data-only same-repository PR jobs;
forks, executable ECS config and Rector use hosted runners before scheduling. No secrets are accepted
by the checking reusable.
- Never copy credentials, change branch protections or make a status required.
- Use `codex/` branches, independent review and exact-SHA evidence before push.
Create/deduplicate the initial issues first. Each PR including a version PR
Expand Down Expand Up @@ -69,7 +71,9 @@ Repository creation, authentication and distribution are separate from local tes
`composer validate --strict`, `php bin/code-standards check --all`,
`actionlint .github/workflows/*.yml`, and `git diff --check`.
Tests use disposable repositories and synthetic files, never consumers' worktrees.
No self-hosted CI dispatch. Record actual commands/results and independent review
Own CI remains hosted. Explicit consumer opt-in may use existing self-hosted
Linux runners only for data-only same-repository PR jobs, with pre-scheduling
hosted fallback for forks, executable ECS config and Rector; no access changes. Record actual commands/results and independent review
for the exact local base/head before publication; do not claim remote CI evidence.

## Child DOX Index
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ never invoked by formatting `check` or `fix`; target PHP and cache remain native
consumer configuration decisions. Custom PHPDoc transformations and deeper
static analysis remain separate; no DevTools extraction parity is asserted.

The reusable workflow accepts `normalize-composer: true` to check the consumer's
root Composer metadata without writes (default: `false`). This project's own CI
enables the check. See [workflow behavior](docs/composer-normalization.rst).

The optional `runs-on` JSON input selects an existing Linux self-hosted runner for
same-repository data-only checks. Forks, executable ECS config and Rector use
hosted Ubuntu. See
[runner trust and requirements](docs/automation.rst).

## 🧰 API summary

The reusable keeps optional analyses disabled by default. Enable
Expand Down
26 changes: 13 additions & 13 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "fast-forward/code-standards",
"type": "library",
"description": "Focused PHP style presets, syntax checks and changed-file automation.",
"license": "MIT",
"type": "library",
"keywords": [
"code-standards",
"code-style",
Expand Down Expand Up @@ -80,28 +80,28 @@
"bin": [
"bin/code-standards"
],
"scripts": {
"test": "phpunit",
"check": [
"@composer validate --strict",
"@composer check-platform-reqs",
"@test",
"@php bin/code-standards check --all"
],
"fix": "@php bin/code-standards fix --all"
},
"config": {
"sort-packages": true,
"allow-plugins": {
"llm/skills": true
},
"platform": {
"php": "8.3.0"
}
},
"sort-packages": true
},
"extra": {
"skills": {
"source": "resources/skills"
}
},
"scripts": {
"check": [
"@composer validate --strict",
"@composer check-platform-reqs",
"@test",
"@php bin/code-standards check --all"
],
"fix": "@php bin/code-standards fix --all",
"test": "phpunit"
}
}
Loading
Loading