Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 13 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
charset = utf-8
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

[{compose,docker-compose}.{yml,yaml}]
indent_size = 4
65 changes: 65 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
APP_NAME=OpenCATS
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US

APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database

# PHP_CLI_SERVER_WORKERS=4

BCRYPT_ROUNDS=12

LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mariadb
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=sail
DB_PASSWORD=password

SESSION_DRIVER=file
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null

BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=sync

CACHE_STORE=file
# CACHE_PREFIX=

MEMCACHED_HOST=127.0.0.1

REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

VITE_APP_NAME="${APP_NAME}"
10 changes: 10 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
* text=auto eol=lf

*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php

/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
122 changes: 72 additions & 50 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: ['8.4.1', '8.5']
# Each version needs a matching Sail runtime directory
# (vendor/laravel/sail/runtimes/<version>); SAIL_RUNTIME selects it.
php-version: ['8.4', '8.5']
env:
# Sail shells out to `docker compose`, which honours COMPOSE_FILE and
# merges the CI-only legacy services from compose.ci.yml into the stack.
COMPOSE_FILE: compose.yaml:compose.ci.yml
SAIL_RUNTIME: ${{ matrix.php-version }}

steps:
- name: Checkout Code
Expand All @@ -35,65 +42,78 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.composer/cache
key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
key: ${{ runner.os }}-composer-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-${{ matrix.php-version }}-
${{ runner.os }}-php-
${{ runner.os }}-composer-${{ matrix.php-version }}-
${{ runner.os }}-composer-

- name: Install Dependencies
run: composer install --no-progress --prefer-dist

- name: PHP Syntax Check (Lint)
run: find src -name "*.php" -print0 | xargs -0 -n1 php -l

- name: Composer Security Audit
# We use || true so legacy vulnerabilities don't block the build
run: composer audit || true
- name: Prepare Laravel environment
run: cp .env.example .env

- name: Create Reports Directory
run: mkdir -p reports/behat-default reports/behat-security test/screenshots
- name: Install Dependencies
run: composer install --no-progress --prefer-dist --no-interaction

- name: Run PHPUnit (Unit Tests)
run: ./vendor/bin/phpunit --log-junit reports/unit-report.xml --testsuite UnitTests
- name: Generate application key
run: php artisan key:generate

- name: Run Integration Tests (Docker)
- name: Prepare directories & permissions
run: |
# 1. Prepare environment files
cp test/config.php ./config.php
touch ./INSTALL_BLOCK

cd docker/
PHP_VERSION=${{ matrix.php-version }} docker compose -f docker-compose-test.yml up -d --build
mkdir -p reports legacy/test/screenshots
chmod -R 777 storage bootstrap/cache

echo "Waiting for BOTH databases..."
opencatsdb_container="$(docker compose -f docker-compose-test.yml ps -q opencatsdb)"
[ -n "$opencatsdb_container" ] || { echo "opencatsdb container ID not found"; exit 1; }
timeout 180s bash -c "until [ \"\$(docker inspect --format '{{.State.Health.Status}}' \"${opencatsdb_container}\" 2>/dev/null)\" = \"healthy\" ]; do sleep 3; done"
integrationtestdb_container="$(docker compose -f docker-compose-test.yml ps -q integrationtestdb)"
[ -n "$integrationtestdb_container" ] || { echo "integrationtestdb container ID not found"; exit 1; }
timeout 180s bash -c "until [ \"\$(docker inspect --format '{{.State.Health.Status}}' \"${integrationtestdb_container}\" 2>/dev/null)\" = \"healthy\" ]; do sleep 3; done"
- name: Prepare legacy test configuration
run: |
cp legacy/test/config.php legacy/config.php
touch legacy/INSTALL_BLOCK

# 2. Pre-clean the integration database
docker compose -f docker-compose-test.yml exec -T integrationtestdb mysql -udev -pdev -e "DROP DATABASE IF EXISTS cats_integrationtest; CREATE DATABASE cats_integrationtest;"
- name: PHP Syntax Check (Lint)
run: |
find app -name "*.php" -print0 | xargs -0 -n1 -P4 php -l
find legacy/src -name "*.php" -print0 | xargs -0 -n1 -P4 php -l

# 3. DIAGNOSTIC: Check if PHP can resolve the database hostname
echo "Diagnostic: Resolving integrationtestdb from PHP container..."
docker compose -f docker-compose-test.yml exec -T php php -r "echo 'IP for integrationtestdb: ' . gethostbyname('integrationtestdb') . PHP_EOL;"
- name: Composer Security Audit
# `|| true` so legacy transitive vulnerabilities don't block the build.
run: composer audit || true

echo "Running PHPUnit Integration Tests..."
docker compose -f docker-compose-test.yml exec -T --workdir /var/www/public php ./vendor/bin/phpunit --log-junit /var/www/public/reports/integration-report.xml --testsuite IntegrationTests
- name: Build Sail image
run: ./vendor/bin/sail build

echo "Running Behat Suites..."
docker compose -f docker-compose-test.yml exec -T --workdir /var/www/public php ./vendor/bin/behat -v -c ./test/behat.yml --suite="default" --format=progress --out=std --format=junit --out=reports/behat-default
docker compose -f docker-compose-test.yml exec -T --workdir /var/www/public php ./vendor/bin/behat -v -c ./test/behat.yml --suite="security" --format=progress --out=std --format=junit --out=reports/behat-security
# continue-on-error: true
- name: Start Sail stack
run: |
./vendor/bin/sail up -d --wait
./vendor/bin/sail ps

- name: Run Laravel tests
run: ./vendor/bin/sail artisan test --log-junit reports/laravel-report.xml

# The legacy suites run inside the app container with cwd=legacy so
# their relative includes (./config.php, ./constants.php, db/, lib/) resolve.
- name: Run legacy Unit tests
run: >
./vendor/bin/sail exec -T laravel.test bash -c
"cd /var/www/html/legacy &&
../vendor/bin/phpunit -c phpunit.xml.dist --testsuite UnitTests
--log-junit /var/www/html/reports/legacy-unit-report.xml"

- name: Run legacy Integration tests
run: >
./vendor/bin/sail exec -T laravel.test bash -c
"cd /var/www/html/legacy &&
../vendor/bin/phpunit -c phpunit.xml.dist --testsuite IntegrationTests
--log-junit /var/www/html/reports/legacy-integration-report.xml"

- name: Run legacy Behat suites
run: |
./vendor/bin/sail exec -T laravel.test bash -c \
"cd /var/www/html/legacy && ../vendor/bin/behat -v -c test/behat.yml --suite=default --format=progress --out=std --format=junit --out=../reports/behat-default"
./vendor/bin/sail exec -T laravel.test bash -c \
"cd /var/www/html/legacy && ../vendor/bin/behat -v -c test/behat.yml --suite=security --format=progress --out=std --format=junit --out=../reports/behat-security"

- name: Docker Diagnostics
- name: Stack diagnostics
if: failure()
run: |
cd docker/
docker compose -f docker-compose-test.yml ps
docker compose -f docker-compose-test.yml logs --tail=200 opencatsdb integrationtestdb php
./vendor/bin/sail ps
./vendor/bin/sail logs --tail=200

- name: Publish Test Report
uses: mikepenz/action-junit-report@v4
Expand All @@ -110,12 +130,12 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: behat-screenshots-php${{ matrix.php-version }}
path: test/screenshots/
path: legacy/test/screenshots/
retention-days: 5

- name: Shutdown Docker
- name: Shutdown Sail
if: always()
run: cd docker && docker compose -f docker-compose-test.yml down
run: ./vendor/bin/sail down -v

release:
name: Create GitHub Release
Expand All @@ -130,7 +150,9 @@ jobs:

- name: Create Release Archive
run: |
zip -r opencats-${{ github.ref_name }}.zip . -x "*.git*" "docker/*" "test/*" "reports/*" ".github/*" "phpunit.xml"
zip -r opencats-${{ github.ref_name }}.zip . \
-x "*.git*" "tests/*" "legacy/test/*" "reports/*" ".github/*" \
"phpunit.xml" "legacy/phpunit.xml.dist" "compose.ci.yml"

- name: Create GitHub Release
env:
Expand Down
40 changes: 25 additions & 15 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
INSTALL_BLOCK
.buildpath
.project
.settings/*
docker/data/*
docker/persist/*
vendor/*
attachments/*
temp/*
!temp/.htaccess
uploads/*
# Ignore Mac DS_Store files
*.log
.DS_Store
/vendor/
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
*.diff
*.rej
/.codex
/.cursor/
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/fonts-manifest.dev.json
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
_ide_helper.php
Homestead.json
Homestead.yaml
Thumbs.db
16 changes: 4 additions & 12 deletions .htaccess
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
IndexIgnore *

Options -Indexes

# Security headers (requires mod_headers; AllowOverride FileInfo or All).
# Basic security headers.
# These defaults are intentionally conservative to avoid breaking common customizations.
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=()"
<IfModule mod_rewrite.c>
RewriteEngine On

# Prevent clickjacking on the OpenCATS UI.
# Note: /careers/ intentionally unsets this header in careers/.htaccess to allow embedding Career Portal into external websites using an iframe.
Header always set X-Frame-Options "SAMEORIGIN"
RewriteRule ^public(/|$) - [L]
RewriteRule ^(.*)$ public/$1 [L]
</IfModule>
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ignore-scripts=true
audit=true
46 changes: 0 additions & 46 deletions README-testing.md

This file was deleted.

8 changes: 8 additions & 0 deletions app/Http/Controllers/Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace App\Http\Controllers;

abstract class Controller
{
//
}
Loading