Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ndavidson7's avatar

Local CI testing using Nektos/Act fails but remote GH Actions succeeds

My GitHub Actions workflow succeeds remotely but when running locally using Act, I get the following error:

SQLSTATE[HY000] [1045] Access denied for user 'root'@'172.18.0.1' (using password: YES) (Connection: mysql, SQL: select table_name as `name`, (data_length + index_length) as `size`, table_comment as `comment`, engine as `engine`, table_collation as `collation` from information_schema.tables where table_schema = 'laravel_app' and table_type in ('BASE TABLE', 'SYSTEM VERSIONED') order by table_name)

I have verified that my database credentials are correct by executing mysql -u root -p on the MySQL Docker container and entering a blank password. I have also tried removing the MYSQL_ALLOW_EMPTY_PASSWORD: true line, adding MYSQL_ROOT_PASSWORD: password, and updating my .env.testing DB_PASSWORD accordingly. I have tried adding a step to clear the cache before running the migrations. I'm at a loss for ideas at this point, so any advice is appreciated.

Workflow:

name: Tests

on: [push, pull_request]

jobs:
  tests:
    name: Run tests
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:latest
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: true
          MYSQL_DATABASE: database
        ports:
          - 3306:3306
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.3"
          extensions: ctype, curl, dom, fileinfo, filter, hash, mbstring, openssl, pcre, pdo, pdo_mysql, session, tokenizer, xml

      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies
        run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "*"
          cache: "npm"

      - name: Install npm dependencies
        run: npm ci --no-fund

      - name: Build assets
        run: npm run build

      - name: Prepare the application
        run: |
          php -r "file_exists('.env') || copy('.env.testing', '.env');"

      - name: Run migrations
        run: php artisan migrate --no-interaction -vvv

      - name: Execute tests
        run: php artisan test

.env.testing:

APP_NAME="Laravel App"
APP_ENV=testing
APP_KEY=base64:+bYGbgBSkFtfCyonpttiBWbv9q1w2MPkt4kpWJaUFCM=
APP_DEBUG=true
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database
DB_USERNAME=root
DB_PASSWORD=

QUEUE_CONNECTION=database
BROADCAST_DRIVER=log
SESSION_DRIVER=array
CACHE_DRIVER=array
0 likes
8 replies
mpilot-sjl's avatar

Crazily, I believe MYSQL_ALLOW_EMPTY_PASSWORD needs to be yes or 1 and true is not valid!

ndavidson7's avatar

@mpilot-sjl Unfortunately, trying this yielded no difference. I should note that the password is correctly being set to empty, as confirmed by manually connecting in the MySQL Docker container.

ndavidson7's avatar

I have since changed the workflow to this:

name: Tests

on: [push, pull_request]

jobs:
  tests:
    name: Run tests
    runs-on: ubuntu-latest

    services:
      mysql:
        image: mysql:latest
        env:
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
          MYSQL_DATABASE: database
        ports:
          - 3306:3306
        options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: "8.3"
          extensions: ctype, curl, dom, fileinfo, filter, hash, mbstring, openssl, pcre, pdo, pdo_mysql, session, tokenizer, xml

      - name: Get composer cache directory
        id: composer-cache
        run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

      - name: Cache dependencies
        uses: actions/cache@v4
        with:
          path: ${{ steps.composer-cache.outputs.dir }}
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: ${{ runner.os }}-composer-

      - name: Install dependencies
        run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "*"
          cache: "npm"

      - name: Install npm dependencies
        run: npm ci --no-fund

      - name: Build assets
        run: npm run build

      - name: Prepare the application
        run: |
          cp .env.testing .env
          php artisan cache:clear
          php artisan config:clear
          php artisan config:cache

      - name: Print env
        run: cat .env

      - name: Print database config
        run: php artisan config:show database.connections.mysql

      - name: Run migrations
        run: php artisan migrate --no-interaction -vvv

      - name: Execute tests
        run: php artisan test

Using this, I was able to trace the problem to the config. The .env is correctly being replaced by .env.testing, as evidenced by cat .env, but the config is still using the values from the original .env. Any ideas as to why this could be?

mpilot-sjl's avatar

@ndavidson7 Does your phpunit.xml file contain any of these settings, specifically in server elements? I had an issue whereby this caught me out as server elements are not overridden by .env, I changed them to env elements and all was good. I don't immediately have any other ideas I'm afraid!

ndavidson7's avatar

@mpilot-sjl This is all that's in my phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory>tests/Feature</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory>app</directory>
        </include>
    </source>
</phpunit>

This may be more of a Docker issue, considering my config is being cached incorrectly, but I appreciate your help nonetheless!

mellymatt's avatar

Hey did you ever figure this out? I'm having a similar issue.

mellymatt's avatar

For anyone looking for a solution here, I eventually just leveraged the --env-file parameter for act which allows you to pass in a local env file.

Please or to participate in this conversation.