Skip to content

Commit

Permalink
feat: Allow a way to fix the timestamp of the PHAR (#1117)
Browse files Browse the repository at this point in the history

Closes #1074.
  • Loading branch information
theofidry authored Nov 7, 2023
1 parent cc73de9 commit 4cfda8d
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 106 deletions.
2 changes: 0 additions & 2 deletions Makefile.e2e
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,6 @@ e2e_reproducible_build: $(SCOPED_BOX_BIN) $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/vend
--config=box.json.dist \
--no-parallel
mv -fv $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/index.phar $(E2E_REPRODUCIBLE_BUILD_BIN_PHAR)
php $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/resign.php $(E2E_REPRODUCIBLE_BUILD_BIN_PHAR)
$(E2E_REPRODUCIBLE_BUILD_BIN_PHAR) \
1>$(E2E_REPRODUCIBLE_BUILD_BIN_ACTUAL_STDOUT) \
2>$(E2E_REPRODUCIBLE_BUILD_BIN_ACTUAL_STDERR)
Expand All @@ -451,7 +450,6 @@ e2e_reproducible_build: $(SCOPED_BOX_BIN) $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/vend
--config=box.json.dist \
--no-parallel
mv -fv $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/index.phar $(E2E_REPRODUCIBLE_BUILD_BIN_PHAR)
php $(E2E_REPRODUCIBLE_BUILD_BIN_DIR)/resign.php $(E2E_REPRODUCIBLE_BUILD_BIN_PHAR)

mv $(E2E_REPRODUCIBLE_BUILD_BIN_PHAR) $(E2E_REPRODUCIBLE_BUILD_BIN_OUTPUT_DIR)/index-2.phar

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ For the full documentation see https://box-project.github.io/box.
1. [Shebang (`shebang`)](doc/configuration.md#shebang-shebang)
1. [Banner (`banner`)](doc/configuration.md#banner-banner)
1. [Banner file (`banner-file`)](doc/configuration.md#banner-file-banner-file)
1. [Forcing the timestamp (`timestamp`)](doc/configuration.md#forcing-the-timestamp-timestamp)
1. [Dumping the Composer autoloader (`dump-autoload`)](doc/configuration.md#dumping-the-composer-autoloader-dump-autoload)
1. [Compactors (`compactors`)](doc/configuration.md#compactors-compactors)
1. [Annotations (`annotations`)](doc/configuration.md#annotations-annotations)
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"psr/log": "^3.0",
"sebastian/diff": "^4.0",
"seld/jsonlint": "^1.9",
"seld/phar-utils": "^1.2",
"symfony/console": "^6.1.7",
"symfony/filesystem": "^6.1.5",
"symfony/finder": "^6.1.3",
Expand Down
50 changes: 49 additions & 1 deletion composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
1. [Shebang (`shebang`)][shebang]
1. [Banner (`banner`)][banner]
1. [Banner file (`banner-file`)][banner-file]
1. [Forcing the timestamp (`timestamp`)][timestamp]
1. [Dumping the Composer autoloader (`dump-autoload`)][dump-autoload]
1. [Compactors (`compactors`)][compactors]
1. [Annotations (`annotations`)][annotations-compactor]
Expand Down Expand Up @@ -92,7 +93,8 @@ to `null`, then its default value will be picked and is strictly equivalent to n
"replacement-sigil": "?",
"replacements": "?",
"shebang": "?",
"stub": "?"
"stub": "?",
"timestamp": "?"
}
```

Expand Down Expand Up @@ -592,6 +594,16 @@ Like banner, the comment must not already be enclosed in a comment block.
If this parameter is set to a different value than `null`, then the value of [`banner`][banner] will be discarded.


## Forcing the timestamp (`timestamp`)

The `timestamp` (`string`|`null`, default `null`) setting will result in Box forcing the timestamp of the PHAR. By
default, the timestamp of the PHAR is the one at which the PHAR was built. It may be useful to fix it for
[reproducible builds][reproducible-builds].

!!! Warning
Forcing the timestamp cannot be done when using an [OpenSSL signature][algorithm].


## Dumping the Composer autoloader (`dump-autoload`)

The `dump-autoload` (`boolean`|`null`, default `true`) setting will result in Box dump the Composer autoload with the
Expand Down Expand Up @@ -1048,9 +1060,11 @@ The short commit hash will only be used if no tag is available.
[placeholders]: #replaceable-placeholders
[replacement-sigil]: #replacement-sigil-replacement-sigil
[replacements]: #replacements-replacements
[reproducible-builds]: reproducible-builds.md#reproducible-builds
[requirement-checker]: requirement-checker.md#requirements-checker
[security]: #security
[shebang]: #shebang-shebang
[timestamp]: #forcing-the-timestamp-timestamp
[the signing best practices]: ./phar-signing.md#phar-signing-best-practices
[stub-stub]: #stub-stub
[stub]: #stub
Expand Down
32 changes: 3 additions & 29 deletions doc/reproducible-builds.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,39 +103,12 @@ By default, Box generates a [banner][banner]. This banners includes the Box vers
different Box versions will result in a different PHAR signature.


### PHAR
### Timestamp

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:

```php
// 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:

```shell
php resign.php app.phar
```

This is obviously not ideal and should be fixed by Box at some point (see [#1074](https://github.com/box-project/box/issues/1074)).
To fix this, you can leverage configure the [timestamp].


## Usages
Expand Down Expand Up @@ -170,3 +143,4 @@ but it is enough to know if the PHARs are identical or not.
[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
[timestamp]: ./configuration.md#forcing-the-timestamp-timestamp
3 changes: 2 additions & 1 deletion fixtures/build/dir020-reproducible-builds/box.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"alias": "e20-app",
"compactors": [
"KevinGH\\Box\\Compactor\\PhpScoper"
]
],
"timestamp": "2020-10-20 10:01:11"
}
27 changes: 0 additions & 27 deletions fixtures/build/dir020-reproducible-builds/resign.php

This file was deleted.

4 changes: 4 additions & 0 deletions res/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,10 @@
"stub": {
"description": "The relative file path to the stub file, or the flag to use the default stub.",
"type": ["boolean", "string", "null"]
},
"timestamp": {
"description": "The time at which the PHAR timestamp will be set.",
"type": ["string", "null"]
}
}
}
29 changes: 25 additions & 4 deletions src/Box.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Amp\MultiReasonException;
use BadMethodCallException;
use Countable;
use DateTimeImmutable;
use Fidry\FileSystem\FS;
use Humbug\PhpScoper\Symbol\SymbolsRegistry;
use KevinGH\Box\Compactor\Compactors;
Expand All @@ -29,6 +30,7 @@
use Phar;
use RecursiveDirectoryIterator;
use RuntimeException;
use Seld\PharUtils\Timestamps;
use SplFileInfo;
use Webmozart\Assert\Assert;
use function Amp\ParallelFunctions\parallelMap;
Expand Down Expand Up @@ -66,7 +68,7 @@ final class Box implements Countable
private array $bufferedFiles = [];

private function __construct(
private readonly Phar $phar,
private Phar $phar,
private readonly string $pharFilePath,
) {
$this->compactors = new Compactors();
Expand Down Expand Up @@ -367,9 +369,28 @@ public function extractTo(string $directory, bool $overwrite = false): void
$this->phar->extractTo($directory, overwrite: $overwrite);
}

public function sign(SigningAlgorithm $signingAlgorithm): void
{
$this->phar->setSignatureAlgorithm($signingAlgorithm->value);
public function sign(
SigningAlgorithm $signingAlgorithm,
?DateTimeImmutable $timestamp = null,
): void {
if (null === $timestamp) {
$this->phar->setSignatureAlgorithm($signingAlgorithm->value);

return;
}

$phar = $this->phar;
$phar->__destruct();
unset($this->phar);

$util = new Timestamps($this->pharFilePath);
$util->updateTimestamps($timestamp);
$util->save(
$this->pharFilePath,
$signingAlgorithm->value,
);

$this->phar = new Phar($this->pharFilePath);
}

/**
Expand Down
Loading

0 comments on commit 4cfda8d

Please sign in to comment.