-
-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: Add documentation for reproducible builds
- Loading branch information
Showing
4 changed files
with
152 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
# Reproducible builds | ||
|
||
1. [PHP-Scoper](#php-scoper) | ||
1. [Composer](#composer) | ||
1. [Composer root version](#composer-root-version) | ||
1. [Composer autoload suffix](#composer-autoload-suffix) | ||
1. [Box](#box) | ||
1. [PHAR alias](#phar-alias) | ||
1. [Requirement Checker](#requirement-checker) | ||
1. [Box banner](#box-banner) | ||
1. [PHAR](#phar) | ||
|
||
|
||
When building a PHAR, you sometimes want to have reproducible builds, i.e. no matter how many times you build the PHAR, | ||
as long as the source content is identical, then the resulting PHAR should not change. | ||
|
||
Whilst this sounds like a good idea and easy at first, it is not the default behaviour. Indeed there is a number of things | ||
that are generated and will make the resulting PHAR different, for example the Composer autoloader classname, or the scoping | ||
prefix if you are using PHP-Scoper. | ||
|
||
This documentation aims at walking you through the common elements to adjust in order to achieve reproducible builds. This | ||
is not an exhaustive piece of documentation as it will also depends on your own application too. | ||
|
||
## PHP-Scoper | ||
|
||
If you are using the [PHP-Scoper compactor][php-scoper-compactor], you will need to define a fixed prefix as otherwise a random | ||
one is generated. | ||
|
||
See the [PHP-Scoper prefix configuration doc][php-scoper-prefix-doc]. | ||
|
||
|
||
## Composer | ||
|
||
### Composer root version | ||
|
||
By default, the git commit of the current version is included in some places in the Composer generated files. At the time | ||
of writing, the current git reference can be found in `vendor/composer/installed.{json|php}` with the path `root.reference`. | ||
|
||
This is not ideal as the content of the PHAR could be identical for two different git commits. In order to get rid of | ||
this problem, you can leverage the [`COMPOSER_ROOT_VERSION`][composer-root-version]. Either by exporting it or passing | ||
it to Box when compiling it: | ||
|
||
``` | ||
$ COMPOSER_ROOT_VERSION=1.0.0-dev box compile | ||
``` | ||
|
||
### Composer autoload suffix | ||
|
||
By default, Box will dump the Composer autoloader which usually results in a different autoloader classname. There is | ||
exceptions to this, for example Composer tend to try to keep the known suffix if one already exist, but it is an exotic | ||
case that is not recommended to rely on. For this reason you need to configure the [Composer autoload prefix][composer-autoload-prefix]: | ||
|
||
``` | ||
$ composer config autoloader-suffix AppChecksum | ||
``` | ||
|
||
Or configure it directly in your `composer.json`: | ||
|
||
``` | ||
{ | ||
"config": { | ||
"autoloader-suffix": "AppChecksum" | ||
} | ||
} | ||
``` | ||
|
||
|
||
## Box | ||
|
||
### PHAR Alias | ||
|
||
By default, Box generates a random PHAR alias so you need to set a fixed value, e.g. `my-app-name`. | ||
|
||
See the [Box alias setting][box-alias]. | ||
|
||
The output (`string`|`null`) setting specifies the file name and path of the newly built PHAR. If the value of the | ||
setting is not an absolute path, the path will be relative to the base path. | ||
|
||
If not provided or set to `null`, the default value used will based on the [`main`][main]. For example if the main file | ||
is `bin/acme.php` or `bin/acme` then the output will be `bin/acme.phar`. | ||
|
||
|
||
### Requirement Checker | ||
|
||
By default, Box includes its [Requirement Checker][requirement-checker]. It will not change from a PHAR to another, so | ||
this step should be skippable. However, the RequirementChecker shipped _does_ change based on the Box version. I.e. | ||
building your PHAR with Box 4.3.8 will result in a different† requirement checker shipped than the one in 4.4.0. | ||
|
||
†: By different is meant the checksum is different. The behaviour and code may be the exact same. The most likely | ||
difference will be the namespace. | ||
|
||
Note that this may change in the future: https://github.com/box-project/box/issues/1075. | ||
|
||
|
||
### Box banner | ||
|
||
By default, Box generates a [banner][banner]. This banners includes the Box version so building the same PHAR with two | ||
different Box versions will result in a different PHAR signature. | ||
|
||
|
||
## PHAR | ||
|
||
The files unix timestamp are part of the PHAR signature, hence if they have a different timestamp (which they do as when | ||
you add a PHAR to a file, it is changed to the time at when you added it). | ||
|
||
To fix this, you can leverage [Seldaek PHAR-Utils][phar-utils] with the following script: | ||
|
||
``` | ||
// resign.php | ||
<?php declare(strict_types=1); | ||
require_once __DIR__ . '/vendor/autoload.php'; | ||
use Seld\PharUtils\Timestamps; | ||
$file = getcwd() . '/' . ($argv[1] ?? ''); | ||
if (!is_file($file)) { | ||
echo "File does not exist.\n"; | ||
exit(1); | ||
} | ||
$util = new Timestamps($file); | ||
$util->updateTimestamps(new DateTimeImmutable('2017-10-11 08:58:00')); | ||
$util->save($file, Phar::SHA512); | ||
``` | ||
|
||
Then once your PHAR is built: | ||
|
||
``` | ||
$ php resign.php app.phar | ||
``` | ||
|
||
This is obviously not ideal and should be fixed by Box at some point (see https://github.com/box-project/box/issues/1074). | ||
|
||
|
||
<br /> | ||
<hr /> | ||
|
||
« [Symfony support](symfony.md#symfony-support) • [FAQ](faq.md#faq) » | ||
|
||
|
||
[banner]: ./configuration.md#banner-banner | ||
[box-alias]: ./configuration.md#alias-alias | ||
[composer-autoload-prefix]: https://getcomposer.org/doc/06-config.md#autoloader-suffix | ||
[composer-root-version]: https://getcomposer.org/doc/03-cli.md#composer-root-version | ||
[phar-utils]: https://github.com/Seldaek/phar-utils | ||
[php-scoper-compactor]: ./configuration.md#compactors-compactors | ||
[php-scoper-prefix-doc]: https://github.com/humbug/php-scoper/blob/main/docs/configuration.md#prefix | ||
[requirement-checker]: ./requirement-checker.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters