Compare commits

...

100 Commits

Author SHA1 Message Date
Michal Kleiner
9881c03c22 Merge branch '2.7' into 2 2023-05-19 22:22:54 +12:00
Guy Sartorelli
e8517ebfb0
Merge pull request #90 from silverstripe/85-implode-args-order
Fix arguments order in SolrIndexCheck
2023-05-19 20:43:40 +12:00
Michal Kleiner
28ca036345
Fix arguments order in SolrIndexCheck 2023-05-19 14:53:43 +12:00
Guy Sartorelli
16caad30b2
Merge branch '2.7' into 2 2023-04-26 12:48:24 +12:00
Maxime Rainville
6f6c30bdcc
Merge pull request #87 from creative-commoners/pulls/2.7/fix-constraints
MNT Revert erroneous dependency changes
2023-03-28 17:15:30 +13:00
Guy Sartorelli
f918209e35
MNT Revert erroneous dependency changes 2023-03-28 14:55:27 +13:00
Maxime Rainville
714de64252
Merge pull request #86 from creative-commoners/pulls/2/dispatch-ci
MNT Use gha-dispatch-ci
2023-03-23 14:10:44 +13:00
Steve Boyd
d9d245a0da MNT Use gha-dispatch-ci 2023-03-21 12:24:56 +13:00
Guy Sartorelli
9d5f8fce7d
MNT Update development dependencies 2023-03-10 16:36:51 +13:00
Guy Sartorelli
f12698f47f
MNT Update release dependencies 2023-03-10 16:36:47 +13:00
Guy Sartorelli
6f0d1c84f2
MNT Update development dependencies 2023-03-10 12:21:31 +13:00
Guy Sartorelli
15a8bca241
Merge pull request #81 from creative-commoners/pulls/2/depr-messages
API Update deprecations
2022-11-21 09:50:03 +13:00
Steve Boyd
94ff5b621c API Update deprecations 2022-11-16 11:31:42 +13:00
Will Rossiter
0e4867f736
DOC add note about FileAccessibilityAndValidationCheck 2022-10-07 09:09:09 +13:00
Steve Boyd
7e59b7e88b Merge branch '2.5' into 2 2022-08-02 18:49:26 +12:00
Steve Boyd
e4b8934148 Merge branch '2.4' into 2.5 2022-08-02 18:49:22 +12:00
Guy Sartorelli
737ac0d8ed
Merge pull request #80 from creative-commoners/pulls/2.4/standardise-modules
MNT Standardise modules
2022-08-02 15:09:01 +12:00
Steve Boyd
3378dc7a99 MNT Standardise modules 2022-08-01 16:21:54 +12:00
Steve Boyd
58caa67c96 Merge branch '2.5' into 2 2022-07-25 11:25:08 +12:00
Steve Boyd
7be4c0dbf3 Merge branch '2.4' into 2.5 2022-07-25 11:25:04 +12:00
Guy Sartorelli
7ba4acc4b2
Merge pull request #79 from creative-commoners/pulls/2.4/module-standards
MNT Use GitHub Actions CI
2022-07-15 17:30:58 +12:00
Steve Boyd
a76c3b89ea MNT Use GitHub Actions CI 2022-07-05 18:55:00 +12:00
Guy Sartorelli
7f6c03b0cb
Merge pull request #78 from wilr/pr/public-privacy
fix: public health/check should not include full details
2022-07-05 17:10:32 +12:00
Will Rossiter
3e3907d14c
fix: public health/check should not include full details 2022-07-05 09:15:03 +12:00
Guy Sartorelli
d3d20e5539
Merge pull request #76 from creative-commoners/pulls/2/php81
ENH PHP 8.1 compatibility
2022-04-26 17:58:17 +12:00
Steve Boyd
b7554a5fc9 ENH PHP 8.1 compatibility 2022-04-13 10:29:17 +12:00
Daniel Hensby
cb13f4ec12
Merge pull request #75 from creative-commoners/pulls/2/php74
DEP Set PHP 7.4 as the minimum version
2022-02-10 11:58:45 +00:00
Steve Boyd
3902a1d688 DEP Set PHP 7.4 as the minimum version 2022-02-10 16:16:07 +13:00
Steve Boyd
aa1311fa01
Merge pull request #72 from creative-commoners/pulls/2/bumpguzzle-requirements
MNT Bump guzzle requirements
2021-11-09 13:13:10 +13:00
Steve Boyd
47b184df5d MNT Fix unit test 2021-11-09 11:35:24 +13:00
Maxime Rainville
94fa4ee1f0 MNT Bump guzzle requirements 2021-11-08 10:32:34 +13:00
Maxime Rainville
3f2fbdaea0
Merge pull request #71 from creative-commoners/pulls/2/sapphire-test-nine
API phpunit 9 support
2021-11-01 21:25:32 +13:00
Steve Boyd
05dd7bc0a7 API phpunit 9 support 2021-10-27 18:06:29 +13:00
Steve Boyd
f6e001bf55 Merge branch '2.3' into 2 2021-05-21 13:50:33 +12:00
Maxime Rainville
e5b77ff325 MNT Remove obsolete branch-alias 2021-05-05 11:17:25 +12:00
Steve Boyd
029078d157
Update build status badge 2021-01-21 16:34:03 +13:00
Steve Boyd
f14fe7c40d Merge branch '2.2' into 2 2021-01-02 20:06:19 +13:00
Maxime Rainville
585b6564b2
Merge pull request #70 from creative-commoners/pulls/2.2/travis-shared
MNT Travis shared config
2020-12-21 15:52:49 +13:00
Maxime Rainville
dd037c8f50
DEP Remove explicit dev requirement for sminnee/phpunit-mock-objects 2020-12-21 14:51:00 +13:00
Steve Boyd
d29a062562 MNT Travis shared config, use sminnee/phpunit 2020-12-01 16:29:13 +13:00
Steve Boyd
2c4d32af6b Merge branch '2.2' into 2 2020-11-12 14:45:10 +13:00
Robbie Averill
7c0b7b0ca7
Merge pull request #68 from creative-commoners/pulls/2.2/travis
Travis 2.2
2020-06-23 10:15:38 -07:00
Steve Boyd
b765ec87c1 Travis 2.2 2020-06-23 12:54:42 +12:00
Steve Boyd
56dab108c9 Require phpunit-mock-objects, bump recipe versions 2020-06-18 13:54:59 +12:00
Steve Boyd
b01567767c Merge branch '2.2' into 2 2020-06-18 11:06:23 +12:00
Maxime Rainville
e19e476cf4
Merge pull request #66 from creative-commoners/2.2
Update for 2.2
2020-06-15 18:32:48 +12:00
Maxime Rainville
dfd9c15d56 Add PHP 7.4 test 2020-06-15 15:52:29 +12:00
Maxime Rainville
23104b77aa Add PHP 7.4 test 2020-06-15 15:48:00 +12:00
Steve Boyd
1aa18e7ced Update for 2.2 2020-06-15 14:53:33 +12:00
Maxime Rainville
08409bb9ca Merge remote-tracking branch 'origin/2.1' into 2 2020-06-12 14:12:14 +12:00
Damian Mooyman
b2f6e06795
Merge pull request #65 from creative-commoners/pulls/2.1/missing-envtypecheck-alias
FIX Add missing aliases for EnvironmentChecks
2020-01-13 11:49:46 +13:00
Garion Herman
0685dfad75 FIX Add missing aliases for EnvironmentChecks 2020-01-06 10:08:08 +13:00
Garion Herman
5f2591a5c1 Merge branch '2.1' into 2 2019-11-18 20:42:46 +13:00
Garion Herman
2bbebc321e Merge branch '2.0' into 2.1 2019-11-18 20:42:15 +13:00
Sam Minnée
9829476dae
Merge pull request #63 from creative-commoners/pulls/2.0/xenial
FIX Update Travis config to Xenial
2019-11-18 19:16:38 +13:00
Garion Herman
49d7d5f2a3 FIX Update Travis config to Xenial 2019-11-18 18:01:51 +13:00
Robbie Averill
f347d1d5c0 Merge branch '2.1' 2019-06-12 10:19:45 +12:00
Serge Latyntcev
c490c4e5a5 ADD ConfirmationMiddleware exceptions for the dev routes 2019-06-12 09:37:05 +12:00
Aaron Carlino
d8452c681a
Merge pull request #1 from silverstripe-security/pulls/master/ss-2018-022
[SS-2018-022] ADD ConfirmationMiddleware exceptions for the dev routes
2019-06-12 09:25:59 +12:00
Serge Latyntcev
e757c9477c ADD ConfirmationMiddleware exceptions for the dev routes 2019-06-12 09:24:52 +12:00
Damian Mooyman
6fe0b1889e
Update master alias to 2.2 2019-04-05 16:02:38 +13:00
Damian Mooyman
40050e9ab4
Update changelog 2019-04-05 16:01:54 +13:00
Robbie Averill
efd996d618
Merge pull request #61 from tractorcow/pulls/2.1/basicauth
BUG Only present basic auth challenge if configured to use it
2019-03-29 11:29:29 +13:00
Robbie Averill
922d810a3a Reduce line length for PSR-2 compatibility 2019-03-29 10:03:02 +13:00
Damian Mooyman
a54400681f
BUG Only present basic auth challenge if configured to use it 2019-03-28 17:21:16 +13:00
Dylan Wagstaff
c5783a2450
Merge pull request #60 from silverstripe-terraformers/feature/extra-checks
Extra checks; cache headers, and session cookies
2019-03-20 11:51:11 +13:00
Frank Mullenger
da9eddc0e1
Merge branch 'master' into feature/extra-checks 2019-03-20 10:23:03 +13:00
Frank Mullenger
8f7f8570f2 NEW: Refactor to provide unit tests for cache headers check. 2019-03-20 10:21:00 +13:00
Frank Mullenger
578c73e6ce NEW: Refactor to provide unit tests for session check. 2019-03-20 09:38:58 +13:00
Robbie Averill
128ddb56ed
Merge pull request #58 from silverstripe-terraformers/feature/env-type-check
NEW: Environment type check.
2019-03-11 13:20:52 +13:00
Frank Mullenger
ace6c51aae FIX: Missed a reference to project code. 2019-03-11 13:03:48 +13:00
Frank Mullenger
540710ab0f NEW: Adding unit test. 2019-03-11 12:44:24 +13:00
Frank Mullenger
2674beb94a FIX: Line length. 2019-02-15 13:58:08 +13:00
Frank Mullenger
90f0556ca4 FIX: Removal of optional param. 2019-02-15 13:52:58 +13:00
Frank Mullenger
27994e51fa FIX: Removing return type declarations. 2019-02-15 13:42:41 +13:00
Guy Marriott
986bc370b9
Update scrutinizer config 2019-02-15 13:10:32 +13:00
Frank Mullenger
c1bfd5640d NEW: Cache headers check. 2019-02-15 11:57:14 +13:00
Frank Mullenger
df59195634 NEW: Session check. 2019-02-15 11:56:32 +13:00
Guy Marriott
f74c371e16
Merge branch '2.0' 2019-02-15 11:43:42 +13:00
Guy Marriott
41763c6042
Merge pull request #59 from creative-commoners/pulls/2.0/update-travis
Update travis configuration
2019-02-15 11:43:12 +13:00
Guy Marriott
f8d35639a0
Update travis configuration 2019-02-15 11:37:55 +13:00
Frank Mullenger
e323674adf NEW: Adding Guzzle dependency. 2019-02-15 11:30:51 +13:00
Frank Mullenger
da6a8a8ee4 MINOR: Adding new check to documentation. 2019-02-15 11:02:13 +13:00
Frank Mullenger
9940c5e8ab FIX: Removing PHP7 return type declaration. 2019-02-15 10:32:13 +13:00
Frank Mullenger
1771a6ef11 NEW: Environment type check. 2019-02-15 10:07:05 +13:00
Robbie Averill
05ac221c2f
Merge pull request #56 from creative-commoners/pulls/master/add-supported-module-badge
Add supported module badge to readme
2018-06-19 09:23:42 +12:00
Dylan Wagstaff
ed61c6bb3a Add supported module badge to readme 2018-06-15 17:34:56 +12:00
Robbie Averill
014c23804f Merge branch '2.0' 2018-05-25 14:55:32 +12:00
Robbie Averill
f6652c2b37 Remove obsolete branch alias 2018-05-25 14:55:17 +12:00
Robbie Averill
161f0aefaf Merge branch '1' 2018-05-03 16:01:24 +12:00
Robbie Averill
a788b37de5 Merge branch '1.2' into 1 2018-05-03 16:00:34 +12:00
Robbie Averill
449a265301 Merge branch '1.1' into 1.2 2018-05-03 16:00:19 +12:00
Dylan Wagstaff
7ad2334f49
Merge pull request #55 from creative-commoners/pulls/1.1/update-travis
Update Travis matrix, Scrutinizer config and readme badges. Use codecov.io
2018-05-03 14:53:59 +12:00
Robbie Averill
250c8d2e00 Use test database in database check test 2018-05-03 11:01:18 +12:00
Robbie Averill
e5651c429c Update Travis matrix, Scrutinizer config and readme badges. Use codecov.io. 2018-05-03 11:01:18 +12:00
Robbie Averill
564936ee01
Remove PHP 5.3 from Travis build matrix 2018-05-03 10:37:28 +12:00
Dylan Wagstaff
b89aefaa20
Merge pull request #54 from creative-commoners/pulls/2.0/fix-solr-check
FIX Implement Solr namespaces into Solr check, remove index filter
2018-01-26 09:51:31 +13:00
Daniel Hensby
152c11638b
Merge branch '1' 2018-01-15 16:31:52 +00:00
Robbie Averill
e6e5ac96df FIX Implement Solr namespaces into Solr check, remove index filter 2017-12-22 15:31:55 +13:00
Daniel Hensby
b78c2af4aa
Updating composer alias 2016-12-28 11:20:58 +00:00
43 changed files with 929 additions and 193 deletions

11
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
ci:
name: CI
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1

16
.github/workflows/dispatch-ci.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: Dispatch CI
on:
# At 1:20 PM UTC, only on Wednesday and Thursday
schedule:
- cron: '20 13 * * 3,4'
jobs:
dispatch-ci:
name: Dispatch CI
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Dispatch CI
uses: silverstripe/gha-dispatch-ci@v1

17
.github/workflows/keepalive.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Keepalive
on:
workflow_dispatch:
# The 4th of every month at 10:50am UTC
schedule:
- cron: '50 10 4 * *'
jobs:
keepalive:
name: Keepalive
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Keepalive
uses: silverstripe/gha-keepalive@v1

View File

@ -1,9 +0,0 @@
inherit: true
checks:
php:
code_rating: true
duplication: true
filter:
paths: [src/*, tests/*]

View File

@ -1,33 +0,0 @@
language: php
env:
global:
- COMPOSER_ROOT_VERSION="2.0.x-dev"
matrix:
include:
- php: 5.6
env: DB=MYSQL PHPCS_TEST=1 PHPUNIT_TEST=1
- php: 7.0
env: DB=PGSQL PHPUNIT_TEST=1
- php: 7.1
env: DB=MYSQL PHPUNIT_COVERAGE_TEST=1
- php: 7.2
env: DB=MYSQL PHPUNIT_TEST=1
before_script:
- phpenv rehash
- phpenv config-rm xdebug.ini
- composer validate
- composer require --no-update silverstripe/recipe-core:1.0.x-dev
- if [[ $DB == PGSQL ]]; then composer require --no-update silverstripe/postgresql:2.0.x-dev; fi
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
script:
- if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi
- if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs src/ tests/ *.php; fi
after_success:
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi

View File

@ -1,10 +1,7 @@
# SilverStripe Environment Checker Module
# Silverstripe Environment Checker Module
[![Build Status](https://travis-ci.org/silverstripe/silverstripe-environmentcheck.svg?branch=master)](https://travis-ci.org/silverstripe/silverstripe-environmentcheck)
[![Code Quality](https://scrutinizer-ci.com/g/silverstripe/silverstripe-environmentcheck/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/silverstripe/silverstripe-environmentcheck/?branch=master)
[![Code Coverage](https://codecov.io/gh/silverstripe/silverstripe-environmentcheck/branch/master/graph/badge.svg)](https://codecov.io/gh/silverstripe/silverstripe-environmentcheck)
[![Version](http://img.shields.io/packagist/v/silverstripe/environmentcheck.svg?style=flat-square)](https://packagist.org/packages/silverstripe/environmentcheck)
[![License](http://img.shields.io/packagist/l/silverstripe/environmentcheck.svg?style=flat-square)](LICENSE.md)
[![CI](https://github.com/silverstripe/silverstripe-environmentcheck/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/silverstripe-environmentcheck/actions/workflows/ci.yml)
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
This module adds an API for running environment checks to your API.
@ -14,10 +11,10 @@ This module adds an API for running environment checks to your API.
## Requirements
* SilverStripe 4.x
* PHP 5.6+
* Silverstripe 4.x
* PHP 7.3
For SilverStripe 3.x support, please use a `1.x` tagged release.
For Silverstripe 3.x support, please use a `1.x` tagged release.
## Aren't these just unit tests?
@ -85,12 +82,17 @@ SilverStripe\EnvironmentCheck\EnvironmentCheckSuite:
* `HasClassCheck`: Check that the given class exists.
This can be used to check that PHP modules or features are installed.
* `FileWriteableCheck`: Check that the given file is writeable.
* `FileAccessibilityAndValidationCheck`: Check that a given file is accessible and optionally matches a given format.
* `FileAgeCheck`: Checks for the maximum age of one or more files or folders.
Useful for files which should be frequently auto-generated,
like static caches, as well as for backup files and folders.
* `ExternalURLCheck`: Checks that one or more URLs are reachable via HTTP.
* `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected.
* `SolrIndexCheck`: Checks if the Solr cores of given class are available.
* `SessionCheck`: Checks that a given URL does not generate a session.
* `CacheHeadersCheck`: Check cache headers in response for directives that must either be included or excluded as well
checking for existence of ETag.
* `EnvTypeCheck`: Checks environment type, dev and test should not be used on production environments.
## Monitoring Checks
@ -106,7 +108,7 @@ SilverStripe\EnvironmentCheck\EnvironmentChecker:
from_email_address: admin@test.com
```
Errors can be logged via the standard SilverStripe PSR-3 compatible logging. Each check will cause an individual log
Errors can be logged via the standard Silverstripe PSR-3 compatible logging. Each check will cause an individual log
entry. You can choose to enable logging separately for warnings and errors, identified through the
result of `EnvironmentCheck->check()`.

View File

@ -2,8 +2,12 @@
Name: environmentcheckinjector
---
SilverStripe\Core\Injector\Injector:
CacheHeadersCheck:
class: SilverStripe\EnvironmentCheck\Checks\CacheHeadersCheck
DatabaseCheck:
class: SilverStripe\EnvironmentCheck\Checks\DatabaseCheck
EnvTypeCheck:
class: SilverStripe\EnvironmentCheck\Checks\EnvTypeCheck
ExternalURLCheck:
class: SilverStripe\EnvironmentCheck\Checks\ExternalURLCheck
FileAccessibilityAndValidationCheck:
@ -22,3 +26,14 @@ SilverStripe\Core\Injector\Injector:
class: SilverStripe\EnvironmentCheck\Checks\SolrIndexCheck
URLCheck:
class: SilverStripe\EnvironmentCheck\Checks\URLCheck
EnvCheckClient:
factory: 'SilverStripe\EnvironmentCheck\Services\ClientFactory'
constructor:
timeout: 10.0
SilverStripe\EnvironmentCheck\Checks\SessionCheck:
dependencies:
client: '%$EnvCheckClient'
SilverStripe\EnvironmentCheck\Checks\CacheHeadersCheck:
dependencies:
client: '%$EnvCheckClient'

View File

@ -12,3 +12,14 @@ SilverStripe\Dev\DevelopmentAdmin:
controller: Silverstripe\EnvironmentCheck\Controllers\DevCheckController
links:
check: 'Run registered environment checks and display their status'
---
Name: environmentcheckroutes-dev_urls-confirmation-exceptions
After:
- 'dev_urls-confirmation-middleware'
---
SilverStripe\Core\Injector\Injector:
DevUrlsConfirmationMiddleware:
properties:
Bypasses:
- '%$SilverStripe\Control\Middleware\ConfirmationMiddleware\UrlPathStartsWith("dev/check")'

View File

@ -4,7 +4,17 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [2.0.0] - unreleased
## [2.1.0]
* Add new checks:
* Environment type
* Session
* Cache Headers
* Fix basic auth
* Add unit tests
* PSR-2 Conformance
## [2.0.0]
* Minimum versions required:
* SilverStripe 4.x

View File

@ -3,7 +3,12 @@
"description": "Provides an API for building environment tests",
"license": "BSD-3-Clause",
"type": "silverstripe-vendormodule",
"keywords": ["silverstripe", "testing", "environment", "check"],
"keywords": [
"silverstripe",
"testing",
"environment",
"check"
],
"authors": [
{
"name": "Will Rossiter",
@ -15,18 +20,16 @@
}
],
"require": {
"silverstripe/framework": "^4.0",
"silverstripe/versioned": "^1.0"
"php": "^7.4 || ^8.0",
"silverstripe/framework": "^4.10",
"silverstripe/versioned": "^1.0",
"guzzlehttp/guzzle": "^6.3.3 || ^7"
},
"require-dev": {
"phpunit/phpunit": "^5.7",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.0"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"extra": [],
"autoload": {
"psr-4": {
"SilverStripe\\EnvironmentCheck\\": "src/",
@ -35,4 +38,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}

View File

@ -2,6 +2,9 @@
<ruleset name="SilverStripe">
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
<file>src</file>
<file>tests</file>
<rule ref="PSR2" >
<!-- Current exclusions -->
<exclude name="PSR1.Methods.CamelCapsMethodName" />

View File

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
<testsuite name="Default">
<directory>tests</directory>
</testsuite>
<testsuites>
<testsuite name="Default">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">

View File

@ -0,0 +1,207 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\Control\Director;
use SilverStripe\Control\Controller;
use SilverStripe\ORM\ValidationResult;
use Psr\Http\Message\ResponseInterface;
use SilverStripe\Core\Config\Configurable;
use SilverStripe\EnvironmentCheck\Traits\Fetcher;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check cache headers for any response, can specify directives that must be included and
* also must be excluded from Cache-Control headers in response. Also checks for
* existence of ETag.
*
* @example SilverStripe\EnvironmentCheck\Checks\CacheHeadersCheck("/",["must-revalidate", "max-age=120"],["no-store"])
* @package environmentcheck
*/
class CacheHeadersCheck implements EnvironmentCheck
{
use Fetcher;
/**
* Settings that must be included in the Cache-Control header
*
* @var array
*/
protected $mustInclude = [];
/**
* Settings that must be excluded in the Cache-Control header
*
* @var array
*/
protected $mustExclude = [];
/**
* Result to keep track of status and messages for all checks, reuses
* ValidationResult for convenience.
*
* @var ValidationResult
*/
protected $result;
/**
* Set up with URL, arrays of header settings to check.
*
* @param string $url
* @param array $mustInclude Settings that must be included in Cache-Control
* @param array $mustExclude Settings that must be excluded in Cache-Control
*/
public function __construct($url = '', $mustInclude = [], $mustExclude = [])
{
$this->setURL($url);
$this->mustInclude = $mustInclude;
$this->mustExclude = $mustExclude;
}
/**
* Check that correct caching headers are present.
*
* @return void
*/
public function check()
{
// Using a validation result to capture messages
$this->result = new ValidationResult();
$response = $this->client->get($this->getURL());
$fullURL = $this->getURL();
if ($response === null) {
return [
EnvironmentCheck::ERROR,
"Cache headers check request failed for $fullURL",
];
}
//Check that Etag exists
$this->checkEtag($response);
// Check Cache-Control settings
$this->checkCacheControl($response);
if ($this->result->isValid()) {
return [
EnvironmentCheck::OK,
$this->getMessage(),
];
} else {
// @todo Ability to return a warning
return [
EnvironmentCheck::ERROR,
$this->getMessage(),
];
}
}
/**
* Collate messages from ValidationResult so that it is clear which parts
* of the check passed and which failed.
*
* @return string
*/
private function getMessage()
{
$ret = '';
// Filter good messages
$goodTypes = [ValidationResult::TYPE_GOOD, ValidationResult::TYPE_INFO];
$good = array_filter(
$this->result->getMessages() ?? [],
function ($val, $key) use ($goodTypes) {
if (in_array($val['messageType'], $goodTypes ?? [])) {
return true;
}
return false;
},
ARRAY_FILTER_USE_BOTH
);
if (!empty($good)) {
$ret .= "GOOD: " . implode('; ', array_column($good ?? [], 'message')) . " ";
}
// Filter bad messages
$badTypes = [ValidationResult::TYPE_ERROR, ValidationResult::TYPE_WARNING];
$bad = array_filter(
$this->result->getMessages() ?? [],
function ($val, $key) use ($badTypes) {
if (in_array($val['messageType'], $badTypes ?? [])) {
return true;
}
return false;
},
ARRAY_FILTER_USE_BOTH
);
if (!empty($bad)) {
$ret .= "BAD: " . implode('; ', array_column($bad ?? [], 'message'));
}
return $ret;
}
/**
* Check that ETag header exists
*
* @param ResponseInterface $response
* @return void
*/
private function checkEtag(ResponseInterface $response)
{
$eTag = $response->getHeaderLine('ETag');
$fullURL = Controller::join_links(Director::absoluteBaseURL(), $this->url);
if ($eTag) {
$this->result->addMessage(
"$fullURL includes an Etag header in response",
ValidationResult::TYPE_GOOD
);
return;
}
$this->result->addError(
"$fullURL is missing an Etag header",
ValidationResult::TYPE_WARNING
);
}
/**
* Check that the correct header settings are either included or excluded.
*
* @param ResponseInterface $response
* @return void
*/
private function checkCacheControl(ResponseInterface $response)
{
$cacheControl = $response->getHeaderLine('Cache-Control');
$vals = array_map('trim', explode(',', $cacheControl ?? ''));
$fullURL = Controller::join_links(Director::absoluteBaseURL(), $this->url);
// All entries from must contain should be present
if ($this->mustInclude == array_intersect($this->mustInclude ?? [], $vals)) {
$matched = implode(",", $this->mustInclude);
$this->result->addMessage(
"$fullURL includes all settings: {$matched}",
ValidationResult::TYPE_GOOD
);
} else {
$missing = implode(",", array_diff($this->mustInclude ?? [], $vals));
$this->result->addError(
"$fullURL is excluding some settings: {$missing}"
);
}
// All entries from must exclude should not be present
if (empty(array_intersect($this->mustExclude ?? [], $vals))) {
$missing = implode(",", $this->mustExclude);
$this->result->addMessage(
"$fullURL excludes all settings: {$missing}",
ValidationResult::TYPE_GOOD
);
} else {
$matched = implode(",", array_intersect($this->mustExclude ?? [], $vals));
$this->result->addError(
"$fullURL is including some settings: {$matched}"
);
}
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\Control\Director;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check whether the environment setting is safe. Useful for live sites where a
* non "Live" setting might disclose sensitive information.
*
* @package environmentcheck
*/
class EnvTypeCheck implements EnvironmentCheck
{
/**
* Check the environment setting.
*
* @return array
*/
public function check()
{
$envSetting = Director::get_environment_type();
switch ($envSetting) {
case 'live':
return [
EnvironmentCheck::OK,
"Env setting is 'live'",
];
// Fallthrough
default:
case 'dev':
case 'test':
return [
EnvironmentCheck::ERROR,
"Env setting is '{$envSetting}' and may disclose information",
];
}
}
}

View File

@ -37,7 +37,7 @@ class ExternalURLCheck implements EnvironmentCheck
public function __construct($urls, $timeout = 15)
{
if ($urls) {
$this->urls = explode(' ', $urls);
$this->urls = explode(' ', $urls ?? '');
}
$this->timeout = $timeout;
}
@ -55,7 +55,7 @@ class ExternalURLCheck implements EnvironmentCheck
foreach ($urls as $url) {
$ch = curl_init();
$chs[] = $ch;
curl_setopt_array($ch, $this->getCurlOpts($url));
curl_setopt_array($ch, $this->getCurlOpts($url) ?? []);
}
// Parallel execution for faster performance
$mh = curl_multi_init();

View File

@ -96,7 +96,7 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
$files = $this->getFiles();
if ($files) {
$fileTypeValidateFunc = $this->fileTypeValidateFunc;
if (method_exists($this, $fileTypeValidateFunc)) {
if (method_exists($this, $fileTypeValidateFunc ?? '')) {
$invalidFiles = [];
$validFiles = [];
@ -109,7 +109,7 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
}
// If at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles ?? []) < count($files ?? [])) {
$validFileList = PHP_EOL;
foreach ($validFiles as $vf) {
$validFileList .= $vf . PHP_EOL;
@ -130,7 +130,7 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
];
}
} else {
if (count($invalidFiles) == 0) {
if (count($invalidFiles ?? []) == 0) {
$checkReturn = [EnvironmentCheck::OK, 'All files valideted'];
} else {
$invalidFileList = PHP_EOL;
@ -180,7 +180,7 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
*/
private function jsonValidate($file)
{
$json = json_decode(file_get_contents($file));
$json = json_decode(file_get_contents($file ?? '') ?? '');
if (!$json) {
return false;
}
@ -204,6 +204,6 @@ class FileAccessibilityAndValidationCheck implements EnvironmentCheck
*/
protected function getFiles()
{
return glob($this->path);
return glob($this->path ?? '');
}
}

View File

@ -96,7 +96,7 @@ class FileAgeCheck implements EnvironmentCheck
*/
public function check()
{
$cutoffTime = strtotime($this->relativeAge, DBDatetime::now()->Format('U'));
$cutoffTime = strtotime($this->relativeAge ?? '', DBDatetime::now()->Format('U'));
$files = $this->getFiles();
$invalidFiles = [];
$validFiles = [];
@ -127,10 +127,10 @@ class FileAgeCheck implements EnvironmentCheck
}
// If at least one file was valid, count as passed
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles ?? []) < count($files ?? [])) {
return [EnvironmentCheck::OK, ''];
}
if (count($invalidFiles) == 0) {
if (count($invalidFiles ?? []) == 0) {
return [EnvironmentCheck::OK, ''];
}
return [
@ -146,6 +146,6 @@ class FileAgeCheck implements EnvironmentCheck
*/
protected function getFiles()
{
return glob($this->path);
return glob($this->path ?? '');
}
}

View File

@ -34,22 +34,22 @@ class FileWriteableCheck implements EnvironmentCheck
if ($this->path[0] == '/') {
$filename = $this->path;
} else {
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path);
$filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path ?? '');
}
if (file_exists($filename)) {
$isWriteable = is_writeable($filename);
if (file_exists($filename ?? '')) {
$isWriteable = is_writeable($filename ?? '');
} else {
$isWriteable = is_writeable(dirname($filename));
$isWriteable = is_writeable(dirname($filename ?? ''));
}
if (!$isWriteable) {
if (function_exists('posix_getgroups')) {
$userID = posix_geteuid();
$user = posix_getpwuid($userID);
$user = posix_getpwuid($userID ?? 0);
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
$currentOwner = posix_getpwuid($currentOwnerID);
$currentOwnerID = fileowner(file_exists($filename ?? '') ? $filename : dirname($filename ?? ''));
$currentOwner = posix_getpwuid($currentOwnerID ?? 0);
$message = "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe file is "
. "currently owned by '$currentOwner[name]'. ";
@ -60,8 +60,8 @@ class FileWriteableCheck implements EnvironmentCheck
$groups = posix_getgroups();
$groupList = [];
foreach ($groups as $group) {
$groupInfo = posix_getgrgid($group);
if (in_array($currentOwner['name'], $groupInfo['members'])) {
$groupInfo = posix_getgrgid($group ?? 0);
if (in_array($currentOwner['name'], $groupInfo['members'] ?? [])) {
$groupList[] = $groupInfo['name'];
}
}

View File

@ -31,7 +31,7 @@ class HasClassCheck implements EnvironmentCheck
*/
public function check()
{
if (class_exists($this->className)) {
if (class_exists($this->className ?? '')) {
return [EnvironmentCheck::OK, 'Class ' . $this->className.' exists'];
}
return [EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist'];

View File

@ -31,7 +31,7 @@ class HasFunctionCheck implements EnvironmentCheck
*/
public function check()
{
if (function_exists($this->functionName)) {
if (function_exists($this->functionName ?? '')) {
return [EnvironmentCheck::OK, $this->functionName . '() exists'];
}
return [EnvironmentCheck::ERROR, $this->functionName . '() doesn\'t exist'];

View File

@ -57,7 +57,7 @@ class SMTPConnectCheck implements EnvironmentCheck
*/
public function check()
{
$f = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
$f = @fsockopen($this->host ?? '', $this->port ?? 0, $errno, $errstr, $this->timeout);
if (!$f) {
return [
EnvironmentCheck::ERROR,
@ -67,7 +67,7 @@ class SMTPConnectCheck implements EnvironmentCheck
fwrite($f, "HELO its_me\r\n");
$response = fread($f, 26);
if (substr($response, 0, 3) != '220') {
if (substr($response ?? '', 0, 3) != '220') {
return [
EnvironmentCheck::ERROR,
sprintf('Invalid mail server response: %s', $response)

View File

@ -0,0 +1,71 @@
<?php
namespace SilverStripe\EnvironmentCheck\Checks;
use Psr\Http\Message\ResponseInterface;
use SilverStripe\EnvironmentCheck\Traits\Fetcher;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Check that a given URL does not generate a session.
*
* @author Adrian Humphreys
* @package environmentcheck
*/
class SessionCheck implements EnvironmentCheck
{
use Fetcher;
/**
* Set up check with URL
*
* @param string $url The route, excluding the domain
* @inheritdoc
*/
public function __construct($url = '')
{
$this->setURL($url);
}
/**
* Check that the response for URL does not create a session
*
* @return array
*/
public function check()
{
$response = $this->client->get($this->getURL());
$cookie = $this->getCookie($response);
$fullURL = $this->getURL();
if ($cookie) {
return [
EnvironmentCheck::ERROR,
"Sessions are being set for {$fullURL} : Set-Cookie => " . $cookie,
];
}
return [
EnvironmentCheck::OK,
"Sessions are not being created for {$fullURL} 👍",
];
}
/**
* Get PHPSESSID or SECSESSID cookie set from the response if it exists.
*
* @param ResponseInterface $response
* @return string|null Cookie contents or null if it doesn't exist
*/
public function getCookie(ResponseInterface $response)
{
$result = null;
$cookies = $response->getHeader('Set-Cookie');
foreach ($cookies as $cookie) {
if (strpos($cookie ?? '', 'SESSID') !== false) {
$result = $cookie;
}
}
return $result;
}
}

View File

@ -3,9 +3,11 @@
namespace SilverStripe\EnvironmentCheck\Checks;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\FullTextSearch\Solr\Solr;
use SilverStripe\FullTextSearch\Solr\SolrIndex;
/**
* Check the availability of all Solr indexes of given class.
* Check the availability of all Solr indexes
*
* If there are no indexes of given class found, the returned status will still be "OK".
*
@ -13,19 +15,6 @@ use SilverStripe\EnvironmentCheck\EnvironmentCheck;
*/
class SolrIndexCheck implements EnvironmentCheck
{
/**
* @var null|string
*/
protected $indexClass;
/**
* @param string $indexClass Limit the index checks to the specified class and all its subclasses.
*/
public function __construct($indexClass = null)
{
$this->indexClass = $indexClass;
}
/**
* {@inheritDoc}
*
@ -35,18 +24,16 @@ class SolrIndexCheck implements EnvironmentCheck
{
$brokenCores = [];
/**
* @todo Revisit this when silverstripe/fulltextsearch has 4.x compat
*/
if (!class_exists('\\Solr')) {
if (!class_exists(Solr::class)) {
return [
EnvironmentCheck::ERROR,
'Class `Solr` not found. Is the fulltextsearch module installed?'
'Class `' . Solr::class . '` not found. Is the fulltextsearch module installed?'
];
}
$service = \Solr::service();
foreach (\Solr::get_indexes($this->indexClass) as $index) {
$service = Solr::service();
foreach (Solr::get_indexes() as $index) {
/** @var SolrIndex $core */
$core = $index->getIndexName();
if (!$service->coreIsActive($core)) {
$brokenCores[] = $core;
@ -56,7 +43,7 @@ class SolrIndexCheck implements EnvironmentCheck
if (!empty($brokenCores)) {
return [
EnvironmentCheck::ERROR,
'The following indexes are unavailable: ' . implode($brokenCores, ', ')
'The following indexes are unavailable: ' . implode(', ', $brokenCores)
];
}

View File

@ -49,7 +49,7 @@ class URLCheck implements EnvironmentCheck
EnvironmentCheck::ERROR,
sprintf('Error retrieving "%s" (Code: %d)', $this->url, $response->getStatusCode())
];
} elseif ($this->testString && (strpos($response->getBody(), $this->testString) === false)) {
} elseif ($this->testString && (strpos($response->getBody() ?? '', $this->testString ?? '') === false)) {
return [
EnvironmentCheck::WARNING,
sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $this->testString)

View File

@ -43,7 +43,11 @@ class DevCheckController extends Controller
$suite = $name;
}
$checker = new EnvironmentChecker($suite, 'Environment status');
/** @var EnvironmentChecker */
$checker = EnvironmentChecker::create($suite, 'Environment status')
->setRequest($request)
->setIncludeDetails(true);
$checker->init($this->config()->permission);
return $checker;

View File

@ -3,6 +3,7 @@
namespace SilverStripe\EnvironmentCheck\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
@ -27,7 +28,6 @@ class DevHealthController extends Controller
public function index()
{
// health check does not require permission to run
$checker = new EnvironmentChecker('health', 'Site health');
$checker->setErrorCode(500);

View File

@ -101,7 +101,7 @@ class EnvironmentCheckSuite
/**
* Run this test suite and return the result code of the worst result.
*
* @return int
* @return EnvironmentCheckSuiteResult
*/
public function run()
{
@ -125,7 +125,7 @@ class EnvironmentCheckSuite
/**
* Get instances of all the environment checks.
*
* @return array
* @return EnvironmentChecker[]
* @throws InvalidArgumentException
*/
protected function checkInstances()

View File

@ -2,8 +2,8 @@
namespace SilverStripe\EnvironmentCheck;
use Psr\Log\LogLevel;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use SilverStripe\Control\Director;
use SilverStripe\Control\Email\Email;
use SilverStripe\Control\HTTPResponse;
@ -12,7 +12,6 @@ use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Security\BasicAuth;
use SilverStripe\Security\Member;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Security;
@ -41,6 +40,11 @@ class EnvironmentChecker extends RequestHandler
*/
protected $title;
/**
* @var bool
*/
protected $includeDetails = false;
/**
* @var int
*/
@ -104,42 +108,32 @@ class EnvironmentChecker extends RequestHandler
if (Environment::getEnv('ENVCHECK_BASICAUTH_USERNAME')
&& Environment::getEnv('ENVCHECK_BASICAUTH_PASSWORD')
) {
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
// authenticate the input user/pass with the configured credentials
if (!(
$_SERVER['PHP_AUTH_USER'] == Environment::getEnv('ENVCHECK_BASICAUTH_USERNAME')
&& $_SERVER['PHP_AUTH_PW'] == Environment::getEnv('ENVCHECK_BASICAUTH_PASSWORD')
)
) {
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e = new HTTPResponse_Exception(null, 401);
$e->setResponse($response);
throw $e;
}
} else {
// Check that details are both provided, and match
if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])
|| $_SERVER['PHP_AUTH_USER'] != Environment::getEnv('ENVCHECK_BASICAUTH_USERNAME')
|| $_SERVER['PHP_AUTH_PW'] != Environment::getEnv('ENVCHECK_BASICAUTH_PASSWORD')
) {
// Fail check with basic auth challenge
$response = new HTTPResponse(null, 401);
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
// Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e = new HTTPResponse_Exception(null, 401);
$e->setResponse($response);
throw $e;
}
} else {
if (!$this->canAccess(null, $permission)) {
return $this->httpError(403);
throw new HTTPResponse_Exception($response);
}
} elseif (!$this->canAccess(null, $permission)) {
// Fail check with silverstripe login challenge
$result = Security::permissionFailure(
$this,
"You must have the {$permission} permission to access this check"
);
throw new HTTPResponse_Exception($result);
}
}
/**
* Determine if the current member can access the environment checker
*
* @param null|int|Member $member
* @param string $permission
*
* @param string $permission
* @return bool
*
* @throws HTTPResponse_Exception
*/
public function canAccess($member = null, $permission = 'ADMIN')
{
@ -147,10 +141,6 @@ class EnvironmentChecker extends RequestHandler
$member = Security::getCurrentUser();
}
if (!$member) {
$member = BasicAuth::requireLogin($this->getRequest(), 'Environment Checker', $permission, false);
}
// We allow access to this controller regardless of live-status or ADMIN permission only
// if on CLI. Access to this controller is always allowed in "dev-mode", or of the user is ADMIN.
if (Director::isDev()
@ -187,19 +177,31 @@ class EnvironmentChecker extends RequestHandler
$response->setStatusCode($this->errorCode);
}
$resultText = $result->customise([
'URL' => Director::absoluteBaseURL(),
'Title' => $this->title,
'Name' => $this->checkSuiteName,
'ErrorCode' => $this->errorCode,
])->renderWith(__CLASS__);
$data = [
'URL' => Director::absoluteBaseURL(),
'Title' => $this->title,
'Name' => $this->checkSuiteName,
'ErrorCode' => $this->errorCode
];
$emailContent = $result->customise(array_merge($data, [
'IncludeDetails' => true
]))->renderWith(__CLASS__);
if (!$this->includeDetails) {
$webContent = $result->customise(array_merge($data, [
'IncludeDetails' => false
]))->renderWith(__CLASS__);
} else {
$webContent = $emailContent;
}
if ($this->config()->get('email_results') && !$result->ShouldPass()) {
$email = new Email(
$this->config()->get('from_email_address'),
$this->config()->get('to_email_address'),
$this->title,
$resultText
$emailContent
);
$email->send();
}
@ -221,14 +223,14 @@ class EnvironmentChecker extends RequestHandler
// output the result as JSON if requested
if ($this->getRequest()->getExtension() == 'json'
|| strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false
|| strpos($this->getRequest()->getHeader('Accept') ?? '', 'application/json') !== false
) {
$response->setBody($result->toJSON());
$response->addHeader('Content-Type', 'application/json');
return $response;
}
$response->setBody($resultText);
$response->setBody($webContent);
return $response;
}
@ -237,80 +239,99 @@ class EnvironmentChecker extends RequestHandler
* Sends a log entry to the configured PSR-3 LoggerInterface
*
* @param string $message
* @param int $level
* @param int $level
*/
public function log($message, $level)
{
Injector::inst()->get(LoggerInterface::class)->log($level, $message);
}
/**
* Set the HTTP status code that should be returned when there's an error.
*
* @param int $errorCode
*
* @return $this
*/
public function setErrorCode($errorCode)
{
$this->errorCode = $errorCode;
return $this;
}
/**
* @deprecated
* Set whether to include the full breakdown of services
*
* @param bool $includeDetails
*
* @return $this
*/
public function setIncludeDetails($includeDetails)
{
$this->includeDetails = $includeDetails;
return $this;
}
/**
* @deprecated 2.0.0 Use config API instead
* @param string $from
*/
public static function set_from_email_address($from)
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
static::config()->set('from_email_address', $from);
}
/**
* @deprecated
* @deprecated 2.0.0 Use config API instead
* @return null|string
*/
public static function get_from_email_address()
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
return static::config()->get('from_email_address');
}
/**
* @deprecated
* @deprecated 2.0.0 Use config API instead
* @param string $to
*/
public static function set_to_email_address($to)
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
static::config()->set('to_email_address', $to);
}
/**
* @deprecated
* @deprecated 2.0.0 Use config API instead
* @return null|string
*/
public static function get_to_email_address()
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
return static::config()->get('to_email_address');
}
/**
* @deprecated
* @deprecated 2.0.0 Use config API instead
* @param bool $results
*/
public static function set_email_results($results)
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
static::config()->set('email_results', $results);
}
/**
* @deprecated
* @deprecated 2.0.0 Use config API instead
* @return bool
*/
public static function get_email_results()
{
Deprecation::notice('2.0', 'Use config API instead');
Deprecation::notice('2.0.0', 'Use config API instead');
return static::config()->get('email_results');
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace SilverStripe\EnvironmentCheck\Services;
use GuzzleHttp\Client as GuzzleClient;
use SilverStripe\Core\Injector\Factory;
use SilverStripe\Core\Config\Configurable;
/**
* Factory class for creating HTTP client which are injected into some env check classes. Inject via YAML,
* arguments for Guzzle client can be supplied using "constructor" property or set as default_config.
*
* @see SilverStripe\EnvironmentCheck\Traits\Fetcher
*/
class ClientFactory implements Factory
{
use Configurable;
/**
* Default config for Guzzle client.
*
* @var array
*/
private static $default_config = [];
/**
* Wrapper to create a Guzzle client.
*
* {@inheritdoc}
*/
public function create($service, array $params = [])
{
return new GuzzleClient($this->getConfig($params));
}
/**
* Merge config provided from yaml with default config
*
* @param array $overrides
* @return array
*/
public function getConfig(array $overrides)
{
return array_merge(
$this->config()->get('default_config'),
$overrides
);
}
}

51
src/Traits/Fetcher.php Normal file
View File

@ -0,0 +1,51 @@
<?php
namespace SilverStripe\EnvironmentCheck\Traits;
use SilverStripe\Control\Director;
/**
* Simple helper for env checks which require HTTP clients.
*
* @package environmentcheck
*/
trait Fetcher
{
/**
* Client for making requests, set vi Injector.
*
* @see SilverStripe\EnvironmentCheck\Services
*
* @var GuzzleHttp\Client
*/
public $client = null;
/**
* Absolute URL for requests.
*
* @var string
*/
protected $url;
/**
* Set URL for requests.
*
* @param string $url Relative URL
* @return self
*/
public function setURL($url)
{
$this->url = Director::absoluteURL($url);
return $this;
}
/**
* Getter for URL
*
* @return string
*/
public function getURL()
{
return $this->url;
}
}

View File

@ -64,16 +64,18 @@
<h1 class="$Status">$Title: $Status</h1>
<h2 class="website">Site: $URL</h2>
<% if $IncludeDetails %>
<table>
<tr><th>Check</th> <th>Status</th> <th>Message</th></tr>
<% loop $Details %>
<tr><td>$Check</td> <td class="$Status">$Status</td> <td>$Message.XML</td></tr>
<% end_loop %>
</table>
<% end_if %>
<% if $ShouldPass %>
<p>Site is available</p>
<p class="subtext">(you may check for the presence of the text 'Site is available' rather than an HTTP $ErrorCode error on this page, if you prefer.)</p>
<p>Site is available</p>
<p class="subtext">(you may check for the presence of the text 'Site is available' rather than an HTTP $ErrorCode error on this page, if you prefer.<% if not $IncludeDetails %> Full details are available for logged in users at <a href="{$AbsoluteBaseURL}dev/check/">dev/check</a><% end_if %>)</p>
<% else %>
<% if $Name == "check" %>
<p><b>A subsystem of the site is unavailable, but the site remains operational</b></p>

View File

@ -0,0 +1,101 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use SilverStripe\Dev\SapphireTest;
use GuzzleHttp\Handler\MockHandler;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\EnvironmentCheck\Checks\CacheHeadersCheck;
/**
* Test session checks.
*/
class CacheHeadersCheckTest extends SapphireTest
{
/**
* Test that directives that must be included, are.
*
* @return void
*/
public function testMustInclude()
{
// Create a mock and queue responses
$mock = new MockHandler([
new Response(200, ['Cache-Control' => 'must-revalidate', 'ETag' => '123']),
new Response(200, ['Cache-Control' =>'no-cache', 'ETag' => '123']),
new Response(200, ['ETag' => '123']),
new Response(200, ['Cache-Control' => 'must-revalidate, private', 'ETag' => '123']),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$cacheHeadersCheck = new CacheHeadersCheck('/', ['must-revalidate']);
$cacheHeadersCheck->client = $client;
// Run checks for each response above
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
}
/**
* Test that directives that must be excluded, are.
*
* @return void
*/
public function testMustExclude()
{
// Create a mock and queue responses
$mock = new MockHandler([
new Response(200, ['Cache-Control' => 'must-revalidate', 'ETag' => '123']),
new Response(200, ['Cache-Control' =>'no-cache', 'ETag' => '123']),
new Response(200, ['ETag' => '123']),
new Response(200, ['Cache-Control' =>'private, no-store', 'ETag' => '123']),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$cacheHeadersCheck = new CacheHeadersCheck('/', [], ["no-store", "no-cache", "private"]);
$cacheHeadersCheck->client = $client;
// Run checks for each response above
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
}
/**
* Test that Etag header must exist in response.
*
* @return void
*/
public function testEtag()
{
// Create a mock and queue responses
$mock = new MockHandler([
new Response(200, ['Cache-Control' => 'must-revalidate', 'ETag' => '123']),
new Response(200, ['Cache-Control' =>'no-cache']),
new Response(200, ['ETag' => '123']),
new Response(200, []),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$cacheHeadersCheck = new CacheHeadersCheck('/');
$cacheHeadersCheck->client = $client;
// Run checks for each response above
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::OK, $cacheHeadersCheck->check());
$this->assertContains(EnvironmentCheck::ERROR, $cacheHeadersCheck->check());
}
}

View File

@ -10,8 +10,6 @@ use SilverStripe\Security\Member;
/**
* Class DatabaseCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DatabaseCheckTest extends SapphireTest

View File

@ -0,0 +1,73 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use SilverStripe\Core\Kernel;
use SilverStripe\Control\Director;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\EnvironmentCheck\Checks\EnvTypeCheck;
/**
* Test the env setting check.
*/
class EnvTypeCheckTest extends SapphireTest
{
/**
* Check is OK when in live mode
*
* @return void
*/
public function testEnvSettingLive()
{
/** @var Kernel $kernel */
$kernel = Injector::inst()->get(Kernel::class);
$kernel->setEnvironment('live');
$this->assertTrue(Director::isLive());
$checker = Injector::inst()->get(EnvTypeCheck::class);
$result = $checker->check();
$this->assertSame($result[0], EnvironmentCheck::OK);
}
/**
* Check is ERROR when in test mode
*
* @return void
*/
public function testEnvSettingTest()
{
/** @var Kernel $kernel */
$kernel = Injector::inst()->get(Kernel::class);
$kernel->setEnvironment('test');
$this->assertTrue(Director::isTest());
$checker = Injector::inst()->get(EnvTypeCheck::class);
$result = $checker->check();
$this->assertSame($result[0], EnvironmentCheck::ERROR);
}
/**
* Check is ERROR when in dev mode
*
* @return void
*/
public function testEnvSettingDev()
{
/** @var Kernel $kernel */
$kernel = Injector::inst()->get(Kernel::class);
$kernel->setEnvironment('dev');
$this->assertTrue(Director::isDev());
$checker = Injector::inst()->get(EnvTypeCheck::class);
$result = $checker->check();
$this->assertSame($result[0], EnvironmentCheck::ERROR);
}
}

View File

@ -9,8 +9,6 @@ use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Class ExternalURLCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class ExternalURLCheckTest extends SapphireTest

View File

@ -9,8 +9,6 @@ use SilverStripe\Dev\SapphireTest;
/**
* Class FileWritableCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class FileWritableCheckTest extends SapphireTest

View File

@ -9,8 +9,6 @@ use SilverStripe\EnvironmentCheck\EnvironmentCheck;
/**
* Class HasClassCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class HasClassCheckTest extends SapphireTest

View File

@ -9,8 +9,6 @@ use SilverStripe\Dev\SapphireTest;
/**
* Class HasFunctionCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class HasFunctionCheckTest extends SapphireTest

View File

@ -0,0 +1,76 @@
<?php
namespace SilverStripe\EnvironmentCheck\Tests\Checks;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use SilverStripe\Dev\SapphireTest;
use GuzzleHttp\Handler\MockHandler;
use SilverStripe\EnvironmentCheck\EnvironmentCheck;
use SilverStripe\EnvironmentCheck\Checks\SessionCheck;
/**
* Test session checks.
*/
class SessionCheckTest extends SapphireTest
{
/**
* @var SilverStripe\EnvironmentCheck\Checks\SessionCheck
*/
public $sessionCheck = null;
/**
* Create a session check for use by tests.
*
* @return void
*/
protected function setUp(): void
{
parent::setUp();
$this->sessionCheck = new SessionCheck('/');
}
/**
* Env check reports error when session cookies are being set.
*
* @return void
*/
public function testSessionSet()
{
// Create a mock and queue two responses.
$mock = new MockHandler([
new Response(200, ['Set-Cookie' => 'PHPSESSID:foo']),
new Response(200, ['Set-Cookie' => 'SECSESSID:bar'])
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$this->sessionCheck->client = $client;
// Check for PHPSESSID
$this->assertContains(EnvironmentCheck::ERROR, $this->sessionCheck->check());
// Check for SECSESSID
$this->assertContains(EnvironmentCheck::ERROR, $this->sessionCheck->check());
}
/**
* Env check responds OK when no session cookies are set in response.
*
* @return void
*/
public function testSessionNotSet()
{
// Create a mock and queue two responses.
$mock = new MockHandler([
new Response(200)
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$this->sessionCheck->client = $client;
$this->assertContains(EnvironmentCheck::OK, $this->sessionCheck->check());
}
}

View File

@ -9,8 +9,6 @@ use SilverStripe\Dev\SapphireTest;
/**
* Class URLCheckTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class URLCheckTest extends SapphireTest

View File

@ -10,8 +10,6 @@ use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
* Class DevCheckControllerTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DevCheckControllerTest extends SapphireTest
@ -30,4 +28,14 @@ class DevCheckControllerTest extends SapphireTest
$this->assertInstanceOf(EnvironmentChecker::class, $controller->index($request));
}
public function testCheckIncludesDetails()
{
$controller = new DevCheckController();
$request = new HTTPRequest('GET', 'example.com');
$response = $controller->index($request)->index();
$this->assertStringContainsString('<table>', $response->getBody());
}
}

View File

@ -10,8 +10,6 @@ use SilverStripe\EnvironmentCheck\EnvironmentChecker;
/**
* Class DevHealthControllerTest
*
* @mixin PHPUnit_Framework_TestCase
*
* @package environmentcheck
*/
class DevHealthControllerTest extends SapphireTest
@ -39,4 +37,15 @@ class DevHealthControllerTest extends SapphireTest
$this->assertInstanceOf(EnvironmentChecker::class, $controller->index($request));
}
public function testHealthDoesNotIncludeDetails()
{
$controller = new DevHealthController();
$request = new HTTPRequest('GET', 'example.com');
$response = $controller->index($request)->index();
$this->assertFalse(strpos($response->getBody(), '<table>'));
}
}

View File

@ -20,7 +20,7 @@ class EnvironmentCheckerTest extends SapphireTest
{
protected $usesDatabase = true;
protected function tearDown()
protected function tearDown(): void
{
EnvironmentCheckSuite::reset();
parent::tearDown();
@ -61,8 +61,8 @@ class EnvironmentCheckerTest extends SapphireTest
$logger->expects($this->once())
->method('log')
->withConsecutive(
$this->equalTo(LogLevel::WARNING),
$this->anything()
[$this->equalTo(LogLevel::WARNING)],
[$this->anything()]
);
Injector::inst()->registerService($logger, LoggerInterface::class);