Skip to content

Behat tests with Github Actions#476

Open
Art4 wants to merge 3 commits into
v2.xfrom
behat-tests-in-github-actions
Open

Behat tests with Github Actions#476
Art4 wants to merge 3 commits into
v2.xfrom
behat-tests-in-github-actions

Conversation

@Art4
Copy link
Copy Markdown
Collaborator

@Art4 Art4 commented May 19, 2026

Another try to run the behat tests with Github Actions.

Summary by CodeRabbit

  • Tests
    • Activated Behat testing against multiple Redmine versions (6.1, 6.0, 5.1) via Docker containers in the GitHub Actions workflow.
    • Enhanced test configuration to support dynamic Redmine instance URLs, improving test flexibility and reliability across different environments.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR enables multi-version Behat testing with Docker containers in GitHub Actions. A new behat job orchestrates starting Redmine 6.1, 6.0, and 5.1 instances on separate localhost ports, polls for readiness, runs test suites, and tears down containers. The test infrastructure is updated to accept and thread configurable Redmine URLs through RedmineInstance, BehatHookTracer, and FeatureContext.

Changes

Multi-version Behat Testing Infrastructure

Layer / File(s) Summary
GitHub Actions Behat job with Docker orchestration
.github/workflows/tests.yml
New behat job configures PHP 8.3, creates version-specific .docker data directories, orchestrates Docker container startup via docker compose up, polls HTTP health endpoints for container readiness with logging fallback, runs Behat suites for Redmine 6.1/6.0/5.1, and ensures cleanup with unconditional docker compose down -v.
Behat suite configuration with per-version Redmine URLs
tests/Behat/behat.yml
The github-actions configuration is updated with rootPath set to .docker and suite-specific redmineUrl values pointing to localhost ports 5061, 5060, and 5051 for Redmine 6.1, 6.0, and 5.1 respectively.
RedmineInstance URL parameter and assignment logic
tests/RedmineExtension/RedmineInstance.php
RedmineInstance::create() and the private constructor accept an optional $redmineUrl parameter. The constructor assigns the provided URL or derives a default from the Redmine version when no URL is supplied.
BehatHookTracer and FeatureContext URL parameter threading
tests/RedmineExtension/BehatHookTracer.php, tests/Behat/Bootstrap/FeatureContext.php
BehatHookTracer::getRedmineInstance() and FeatureContext::__construct() are updated to accept an optional $redmineUrl parameter and forward it through the initialization chain, enabling Behat configuration to specify per-version Redmine URLs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested labels

enhancement

Suggested reviewers

  • kbsali

Poem

🐰 Docker containers dance in perfect rows,
Three Redmine versions on localhost flows,
URLs thread through the bootstrap chain,
Making tests parallel—no more migraine!
Behat suites run fast, the workflow's clean,
Multi-version testing like you've never seen! 🚀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: enabling Behat tests to run in GitHub Actions through workflow configuration and supporting code updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch behat-tests-in-github-actions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.72%. Comparing base (969291d) to head (3521c10).

Additional details and impacted files
@@            Coverage Diff            @@
##               v2.x     #476   +/-   ##
=========================================
  Coverage     98.72%   98.72%           
  Complexity      783      783           
=========================================
  Files            29       29           
  Lines          2275     2275           
=========================================
  Hits           2246     2246           
  Misses           29       29           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Art4 Art4 force-pushed the behat-tests-in-github-actions branch from a43fc32 to 4c8ec52 Compare May 19, 2026 18:15
@Art4 Art4 marked this pull request as ready for review May 19, 2026 18:29
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
.github/workflows/tests.yml (1)

96-103: ⚡ Quick win

Run all Behat suites even if one fails.

With separate steps, the first failing suite prevents later suites from running. Consider aggregating exit codes in a single step so all suites execute and the job still fails at the end.

🔧 Proposed refactor
-      - name: Run behat [Redmine 6.1]
-        run: vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_6_1
-
-      - name: Run behat [Redmine 6.0]
-        run: vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_6_0
-
-      - name: Run behat [Redmine 5.1]
-        run: vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_5_1
+      - name: Run behat suites
+        run: |
+          status=0
+          vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_6_1 || status=$?
+          vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_6_0 || status=$?
+          vendor/bin/behat --config tests/Behat/behat.yml --profile=github-actions --format=progress --suite=redmine_5_1 || status=$?
+          exit $status
🤖 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/tests.yml around lines 96 - 103, The three separate GitHub
Actions steps running Behat (suites redmine_6_1, redmine_6_0, redmine_5_1)
should be combined into a single step that runs all suites and aggregates their
exit codes so later suites still execute; update the step that currently runs
vendor/bin/behat --suite=redmine_6_1, --suite=redmine_6_0 and
--suite=redmine_5_1 to invoke each suite sequentially, capture each command's
exit status, and at the end exit with a non-zero code if any of the captured
statuses are non-zero (so the job fails if any suite failed but all suites run).
🤖 Prompt for all review comments with 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.

Inline comments:
In @.github/workflows/tests.yml:
- Around line 40-42: The behat job inherits broad GITHUB_TOKEN permissions;
restrict it by adding a permissions block under the job named "behat" that
grants least privilege (e.g., at minimum set contents: read and any other
specific read-only scopes your tests require) so the job no longer inherits wide
default permissions from the workflow root; update the job definition in the
.github/workflows/tests.yml for the behat job to include this permissions block.
- Around line 51-65: The workflow uses floating tags for actions
(actions/checkout@v4, shivammathur/setup-php@v2, ramsey/composer-install@v2) and
the checkout step lacks persist-credentials: false; fix by replacing each action
tag with its corresponding full 40-character commit SHA for supply-chain safety
and add persist-credentials: false under the Checkout step (the actions/checkout
usage) to prevent passing repo credentials to later steps; ensure the SHAs are
verified from each action's GitHub repository and update the workflow
accordingly.

---

Nitpick comments:
In @.github/workflows/tests.yml:
- Around line 96-103: The three separate GitHub Actions steps running Behat
(suites redmine_6_1, redmine_6_0, redmine_5_1) should be combined into a single
step that runs all suites and aggregates their exit codes so later suites still
execute; update the step that currently runs vendor/bin/behat
--suite=redmine_6_1, --suite=redmine_6_0 and --suite=redmine_5_1 to invoke each
suite sequentially, capture each command's exit status, and at the end exit with
a non-zero code if any of the captured statuses are non-zero (so the job fails
if any suite failed but all suites run).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c0426ce9-96d1-4653-84a9-be0502d17139

📥 Commits

Reviewing files that changed from the base of the PR and between 969291d and 3521c10.

📒 Files selected for processing (5)
  • .github/workflows/tests.yml
  • tests/Behat/Bootstrap/FeatureContext.php
  • tests/Behat/behat.yml
  • tests/RedmineExtension/BehatHookTracer.php
  • tests/RedmineExtension/RedmineInstance.php

Comment on lines +40 to +42
behat:
name: Tests (Behat with PHP ${{ matrix.php }})
runs-on: ubuntu-latest
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restrict token scope for the new behat job.

Add a permissions block with least privilege so this job doesn’t inherit broad default GITHUB_TOKEN permissions.

🔧 Proposed fix
   behat:
     name: Tests (Behat with PHP ${{ matrix.php }})
     runs-on: ubuntu-latest
+    permissions:
+      contents: read
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
behat:
name: Tests (Behat with PHP ${{ matrix.php }})
runs-on: ubuntu-latest
behat:
name: Tests (Behat with PHP ${{ matrix.php }})
runs-on: ubuntu-latest
permissions:
contents: read
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 40-107: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)

🤖 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/tests.yml around lines 40 - 42, The behat job inherits
broad GITHUB_TOKEN permissions; restrict it by adding a permissions block under
the job named "behat" that grants least privilege (e.g., at minimum set
contents: read and any other specific read-only scopes your tests require) so
the job no longer inherits wide default permissions from the workflow root;
update the job definition in the .github/workflows/tests.yml for the behat job
to include this permissions block.

Comment on lines +51 to +65
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Setup PHP, with composer and extensions
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: phpunit
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, curl
coverage: xdebug

- name: Install Composer dependencies
uses: ramsey/composer-install@v2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/tests.yml"

echo "Potentially unpinned uses: references (not full 40-char SHA):"
rg -n '^\s*uses:\s*[^@]+@(?![0-9a-fA-F]{40}\b).+$' "$file" || true

echo
echo "Checkout steps missing persist-credentials: false (manual check context shown):"
rg -n -A6 -B1 'uses:\s*actions/checkout@' "$file"

Repository: kbsali/php-redmine-api

Length of output: 1278


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/workflows/tests.yml"

echo "=== All 'uses:' references in the file ==="
rg -n 'uses:' "$file"

echo
echo "=== Lines 51-65 (target of review) ==="
sed -n '51,65p' "$file" | cat -n

echo
echo "=== Count of unpinned vs pinned actions ==="
echo "Using version tags (unpinned):"
rg 'uses:.*`@v`[0-9]' "$file" | wc -l

echo "Using full SHAs (pinned):"
rg 'uses:.*@[0-9a-fA-F]{40}' "$file" | wc -l

Repository: kbsali/php-redmine-api

Length of output: 1328


🌐 Web query:

GitHub Actions security best practices pin action SHA commit credentials

💡 Result:

Pinning GitHub Actions to a full-length commit SHA is a critical security best practice to prevent supply chain attacks, such as tag hijacking or malicious code injection [1][2][3]. Why Pinning to SHA is Required GitHub Actions referenced by tags (e.g., @v1) or branches (e.g., @main) are mutable, meaning the underlying code can be changed by the action maintainer or an attacker who gains access to the repository [2][3][4]. Pinning to a full-length (40-character) commit SHA ensures that your workflow always executes the exact, immutable version of the code you have verified [2][3][5]. This is currently the only way to use an action as an immutable release [6][7][3]. How to Pin Actions To pin an action, replace the tag or branch reference with the full-length commit SHA of the desired version [2][3]. Example: uses: actions/checkout@v4 # Vulnerable to tag manipulation uses: actions/checkout@11bd719 # Secure, pinned to SHA Best Practices for Maintenance 1. Use Version Comments: Always include the original version tag in a comment next to the SHA to make it easier to identify which version is being used and to facilitate manual updates [1][8][3]. 2. Automate Updates: Because SHA pinning requires manual updates to receive bug fixes and security patches, use tools like Dependabot or Renovate to automatically propose updates to your pinned SHAs [1][8][3][5]. 3. Verify Source: Ensure the SHA originates from the official action repository and not a fork [9][6][3]. 4. Enforce via Policy: Organizations can enforce this practice at the repository or organization level by enabling the "Require actions to be pinned to a full-length commit SHA" policy in GitHub Actions settings [6][10][11]. When enabled, any workflow using a non-SHA reference will fail [10][4][11]. 5. Use Security Auditing Tools: Tools like zizmor can automatically detect unpinned action references in your workflows [8][12][13]. Regarding Credentials While SHA pinning protects the integrity of the action code itself, it does not inherently protect against credential theft if the action is malicious or compromised [14]. Always follow the principle of least privilege by: - Setting default GITHUB_TOKEN permissions to read-only [15][7]. - Using OpenID Connect (OIDC) to access cloud resources instead of storing long-term secrets in GitHub [16]. - Auditing the permissions and network access required by third-party actions [15][17].

Citations:


🌐 Web query:

GitHub checkout action persist-credentials false security best practice

💡 Result:

Setting persist-credentials: false in the actions/checkout GitHub Action is considered a security best practice to minimize the risk of credential exposure [1][2]. By default, actions/checkout configures the local Git environment with the authentication token (such as the GITHUB_TOKEN) used to clone the repository [3][4]. This makes the token available to any subsequent steps or scripts running within the same job, as they can read it from the Git configuration [5][2]. If a workflow step is compromised or if the repository is inadvertently archived and uploaded as an artifact, this token could be exposed [6][2]. To mitigate this risk, you should explicitly disable this behavior when the token is not required for subsequent Git operations [1]: - uses: actions/checkout@v4 with: persist-credentials: false While recent updates to actions/checkout have improved security by moving these credentials to a separate file in $RUNNER_TEMP rather than directly in.git/config [3][7], setting persist-credentials: false remains the recommended approach to follow the principle of least privilege and prevent unnecessary credential persistence [1][2]. If your workflow does not need to perform authenticated Git operations (like git push or git submodule updates) after the initial checkout, there is no reason to keep the credentials active [1].

Citations:


Pin action references to full commit SHAs and add persist-credentials: false to checkout.

All actions in this workflow use version tags (@v4, @v2, etc.) instead of full 40-character commit SHAs, creating supply-chain attack risk. Additionally, the checkout step should set persist-credentials: false to avoid unnecessarily exposing credentials to subsequent steps.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 51-54: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 52-52: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 57-57: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 65-65: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/tests.yml around lines 51 - 65, The workflow uses floating
tags for actions (actions/checkout@v4, shivammathur/setup-php@v2,
ramsey/composer-install@v2) and the checkout step lacks persist-credentials:
false; fix by replacing each action tag with its corresponding full 40-character
commit SHA for supply-chain safety and add persist-credentials: false under the
Checkout step (the actions/checkout usage) to prevent passing repo credentials
to later steps; ensure the SHAs are verified from each action's GitHub
repository and update the workflow accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant