Seven Commands to Bulletproof Your Symfony Application CI Build
January 12, 2020 • 5 minutes read • 0 comments • Edit on GitHub
Over the course of years, I noticed there are more and more checks that are usually performed in our Symfony applications’ CI environment. This is my attempt at writing down the most useful ones.
Table of contents:
- Checking for security vulnerabilities
- Validating package configuration
- Linting Symfony container
- Linting Twig templates
- Linting YAML files
- Testing Doctrine migrations
- Validating Doctrine mappings
1. Checking for security vulnerabilities
Security should be the most critical concern while developing any application. It should come as no surprise that there are multiple solutions for ensuring that our application does not rely on dependencies with known vulnerabilities. Although they differ in usage, they are all based on the same source - FriendsOfPHP/security-advisories.
Symfony CLI
It is provided together with the Symfony binary, which is a recommended way to create new Symfony projects and includes a convenient local web server, which comes handy during development.
If you already use it as a web server in your CI build, I would recommend using it also for security checks.
symfony security:check
If you do not have it in your CI build yet, the following .travis.yml
configuration does the job:
cache:
directories:
- ~/.symfony
before_install:
- |
if [ ! -f ~/.symfony/bin/symfony ]; then
wget https://get.symfony.com/cli/installer -O - | bash
fi
script:
- ~/.symfony/bin/symfony security:check
SensioLabs Security Checker
SensioLabs/SecurityChecker is what I’ve been using before switching to Symfony CLI. It uses security.symfony.com
API
to perform the check, which means your composer.lock
will be uploaded there.
To use it, add sensiolabs/security-checker
to your require-dev
section in composer.json
and then run the following command:
vendor/bin/security-checker security:check
Roave Security Advisories
While the previous two tools work in a similar way, Roave/SecurityAdvisories takes a different approach.
It is a Composer package which defines vulnerable packages as its conflicts, preventing them from being installed and resulting in irresolvable dependencies. This behaviour is a double-edged sword - it does not trigger when packages dependencies are installed from the lock file.
My recommendation is to require this package only in the CI build:
composer install
composer require --dev roave/security-advisories
However, resolving dependencies in complex projects takes a lot of time, which makes me prefer the other solutions.
2. Validating package configuration
Composer provides a command to validate your composer.json
and composer.lock
files. It checks whether your lock file
is up-to-date, whether used constraints are not too loose or too strict and whether the package is valid to be published on Packagist.
composer validate --strict
There are a few switches available for this command:
-
--strict
Makes the command return non-zero code for warnings as well as errors. For example, having overly strict dependency (
1.0.0
instead of^1.0
) inrequire
section will trigger a warning. -
--no-check-all
Disables checking for overly strict or unbound dependencies in
require
section. Even without this switch, it does not check the dependencies defined inrequire-dev
section. -
--no-check-lock
Disables checking whether the lock file is up-to-date.
-
--no-check-publish
Ignores errors which prevent the package from be published on Packagist. Useful for internal applications that will not be published, but required for open source packages.
I would recommend you starting with the most strict check and ignoring some parts later if needed.
3. Linting Symfony container
Introduced with Symfony 4.4, linting the container might help in finding dead services configurations. We found a few in Sylius and decided to add it to the build to prevent us from introducing them anymore.
bin/console lint:container
4. Linting Twig templates
Linting your Twig templates checks their syntax and might detect unused templates if an unexisting filter or function is used in those. After running it on Sylius codebase, it has found a template calling parent blocks while not extending any template itself and another template calling an unexisting filter.
bin/console lint:twig templates
Starting from Symfony 4.4, this command also includes a way to report usages of deprecated Twig features. It helped greatly with the upgrade to Twig 3.
bin/console lint:twig templates--show-deprecations
I would not recommend adding deprecation checks to your CI build as it would make it more unstable - any deprecation in next Twig version would make it fail.
5. Linting YAML files
It is easy to make errors writing YAML files compared to XML. Therefore, it is essential to get feedback on those as fast as possible.
bin/console lint:yaml config src translations
6. Testing Doctrine migrations
If you provide Doctrine migrations in your application, it is desirable to test them. Most applications include the following line in their CI builds:
bin/console doctrine:migrations:migrate --no-interaction
While this covers the most common path, it does not test reverting these migrations.
bin/console doctrine:migrations:migrate --no-interaction
bin/console doctrine:migrations:migrate first --no-interaction
bin/console doctrine:migrations:migrate --no-interaction
These three commands will first create the schema in the database, then revert the changes and create it once again.
7. Validating Doctrine mappings
After the migrations have been run or the database schema has been synchronised in any other way, it’s worth to validate your Doctrine mappings and whether they’re correctly synchronised with the database schema.
It can be done with the following command:
bin/console doctrine:schema:validate
Conclusion
Surely, this list is non-exhaustive: it completely misses static analysers, testing frameworks, coding standard fixers and automation tools, which I would like to include in another blog post in this series.
What it mainly focuses on are commands that can be added with little effort but might be often overlooked. If you use one of those, but it wasn’t mentioned above, let me know in the comments!
Subscribe to the newsletter
Stay up to date with my content. Opt-out at any time.I'm Kamil Kokot. My goal is to make software testing as effortless as possible so that you can develop with confidence. I maintain Behat and FriendsOfBehat libraries.
Over the course of years, I noticed there are more and more checks that are usually performed in our #symfony applications’ CI environment. This is my attempt at writing down the most useful ones. https://t.co/XGJF0jTd13
— Kamil Kokot (@pamilme) January 13, 2020