Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
1e85222
Work in progress
phenaproxima Mar 5, 2021
a7a7997
Pass TUF repo to HttpDownloader.
phenaproxima Mar 17, 2021
e779856
Use HttpDownloaderAdapter as a central registry of TUF instances
phenaproxima Mar 18, 2021
35a09b5
Might have fixed it
phenaproxima Mar 18, 2021
4043b66
Pass target key through to to downloader
phenaproxima Mar 18, 2021
57c3c03
Pry into factory to init default installers
phenaproxima Mar 18, 2021
d858d8e
Set global loop
phenaproxima Mar 18, 2021
0b1188a
Giant god damn mess
phenaproxima Mar 19, 2021
8e492cf
Create uninstall routine
phenaproxima Mar 19, 2021
e12f8a9
Make it easier to swap the downloader
phenaproxima Mar 19, 2021
f01e30d
Add UrlMap decorator
phenaproxima Mar 19, 2021
42d3241
Clean up PackageLoader
phenaproxima Mar 19, 2021
5da2538
Make UrlMapDecorator an ArrayObject
phenaproxima Mar 19, 2021
dc0e2c6
Clean up repo parts
phenaproxima Mar 19, 2021
b807213
Fix bad factory invocations
phenaproxima Mar 19, 2021
afa3491
Document repo constructor logic
phenaproxima Mar 19, 2021
229cbd4
Minor cleanup in HttpDownloader
phenaproxima Mar 19, 2021
acbb3ff
Use array for promise queue
phenaproxima Mar 20, 2021
544703d
Add accessor for decorated downloader
phenaproxima Mar 20, 2021
3a9ad57
Use event to handle processed URL
phenaproxima Mar 22, 2021
ce80bf8
A bit of documentation
phenaproxima Mar 22, 2021
dfa0254
Rename register() to addRepository()
phenaproxima Mar 22, 2021
40f8119
Docs
phenaproxima Mar 22, 2021
3e05b00
Tiny fixes
phenaproxima Mar 23, 2021
392618e
Use package name and version to identify targets
phenaproxima Mar 23, 2021
a1f547e
Document addRepository()
phenaproxima Mar 23, 2021
82a457a
Remove UrlMapDecorator
phenaproxima Mar 23, 2021
ab61dd0
Fix bad invocation
phenaproxima Mar 23, 2021
f0c57d6
Always queue our promises
phenaproxima Mar 23, 2021
c03fab6
Remove unnecessary use
phenaproxima Mar 23, 2021
1aaf023
Address Ted feedback
phenaproxima Mar 23, 2021
8908000
Handle HTTP headers and fix a bug
phenaproxima Apr 1, 2021
f5882bc
Handle 304 responses
phenaproxima Apr 1, 2021
012345f
Improve comments.
phenaproxima Apr 1, 2021
f9f8b7a
Start adding a unit test.
phenaproxima Apr 1, 2021
aefde20
Start adjusting files for CI testing
phenaproxima Apr 2, 2021
6ea7f06
Fix typo in packages.json
phenaproxima Apr 2, 2021
8f0d950
Merge branch 'main' into wip
phenaproxima Apr 2, 2021
51f2cc5
Merge branch 'main' into wip
phenaproxima Apr 2, 2021
fd5d022
Add more unit tests
phenaproxima Apr 5, 2021
bf304a2
Add more test cases
phenaproxima Apr 5, 2021
6eaaffe
Handle NotFoundException
phenaproxima Apr 5, 2021
355c1a3
Moar test coverage
phenaproxima Apr 5, 2021
e901f53
Require dev-master of composer/composer.
phenaproxima Apr 12, 2021
c8e39e1
Remove scary things
phenaproxima Apr 12, 2021
c709785
Awww yeah, working proof of concept
phenaproxima Apr 12, 2021
eb4edcf
Remove HttpDownloaderTest
phenaproxima Apr 12, 2021
ed4a40f
Clean up and comment
phenaproxima Apr 12, 2021
2e52838
Constrain download size and remove PHPUnit
phenaproxima Apr 15, 2021
0324d24
Revert changes to test project composer.json and remove old TUF root …
phenaproxima Apr 15, 2021
0162580
Use GITHUB_HEAD_REF in workflow
phenaproxima Apr 15, 2021
7b3d1b3
Symlink packages.json for CI
phenaproxima Apr 15, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-fixture.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ jobs:
- name: Start PHP server
run: 'php -S localhost:8080 &'
- name: Install test project dependencies
run: 'composer require php-tuf/composer-integration:dev-composer-actions'
run: 'composer require php-tuf/composer-integration:dev-${{ env.GITHUB_HEAD_REF }}'
working-directory: ./fixtures/test-project
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"class": "Tuf\\ComposerIntegration\\Plugin"
},
"require-dev": {
"composer/composer": "^2"
"composer/composer": "dev-master"
},
"scripts": {
"post-install-cmd": [
Expand Down
288 changes: 182 additions & 106 deletions composer.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion fixtures/targets/packages.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"packages": [],
"metadata-url": "/files/packages/8/p2/%package%.json",
"metadata-url": "/targets/files/packages/8/p2/%package%.json",
"available-package-regexes": ["drupal/*"]
}
87 changes: 0 additions & 87 deletions fixtures/test-project/tuf-root.json

This file was deleted.

131 changes: 127 additions & 4 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,92 @@
namespace Tuf\ComposerIntegration;

use Composer\Composer;
use Composer\Config;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PluginInterface;
use Composer\Plugin\PostFileDownloadEvent;
use Composer\Repository\ComposerRepository;
use Composer\Repository\RepositoryFactory;
use Composer\Repository\RepositoryManager;
use Tuf\ComposerIntegration\Repository\TufValidatedComposerRepository;
use Composer\Util\Filesystem;

class Plugin implements PluginInterface
class Plugin implements PluginInterface, EventSubscriberInterface
{
/**
* The repository manager.
*
* @var RepositoryManager
*/
private $repositoryManager;

/**
* {@inheritDoc}
*/
public static function getSubscribedEvents()
{
return [
PluginEvents::POST_FILE_DOWNLOAD => ['postFileDownload', -1000],
];
}

/**
* Reacts when a file, or metadata, is downloaded.
*
* If the downloaded file or metadata is associated with a TUF-aware Composer
* repository, then the downloaded data will be validated by TUF.
*
* @param PostFileDownloadEvent $event
* The event object.
*/
public function postFileDownload(PostFileDownloadEvent $event): void
{
$type = $event->getType();
/** @var array|PackageInterface $context */
$context = $event->getContext();

if ($type === 'metadata') {
if ($context['repository'] instanceof TufValidatedComposerRepository) {
$context['repository']->validateMetadata($event->getUrl(), $context['response']);
}
} elseif ($type === 'package') {
// The repository URL is saved in the package's transport options so that
// it will persist even when loaded from the lock file.
// @see \Tuf\ComposerIntegration\TufValidatedComposerRepository::configurePackageTransportOptions()
$options = $context->getTransportOptions();
if (array_key_exists('tuf', $options)) {
$repository = $this->getRepositoryByUrl($options['tuf']['repository']);
if ($repository) {
$repository->validatePackage($context, $event->getFileName());
}
}
}
}

/**
* Looks up a TUF-validated Composer repository by its URL.
*
* @param string $url
* The repository URL.
* @return TufValidatedComposerRepository|null
* The TUF-validated Composer repository with the given URL, or NULL if none
* is currently registered.
*/
private function getRepositoryByUrl(string $url): ?TufValidatedComposerRepository
{
foreach ($this->repositoryManager->getRepositories() as $repository) {
if ($repository instanceof TufValidatedComposerRepository) {
$config = $repository->getRepoConfig();
if ($config['url'] === $url) {
return $repository;
}
}
}
return null;
}

/**
* {@inheritDoc}
*/
Expand All @@ -26,8 +103,23 @@ public function activate(Composer $composer, IOInterface $io)
$newManager = $this->createNewRepositoryManager($composer, $io);
$this->addTufValidationToRepositories($composer, $newManager, $io);
$composer->setRepositoryManager($newManager);
$this->repositoryManager = $composer->getRepositoryManager();
}

/**
* Creates a new repository manager.
*
* The new repository manager will allow Composer repositories to opt into
* TUF protection.
*
* @param Composer $composer
* The Composer instance.
* @param IOInterface $io
* The I/O service.
*
* @return RepositoryManager
* The new repository manager.
*/
private function createNewRepositoryManager(Composer $composer, IOInterface $io): RepositoryManager
{
$loop = $composer->getLoop();
Expand All @@ -40,6 +132,16 @@ private function createNewRepositoryManager(Composer $composer, IOInterface $io)
return $newManager;
}

/**
* Adds TUF validation to already-instantiated Composer repositories.
*
* @param Composer $composer
* The Composer instance.
* @param RepositoryManager $manager
* The repository manager.
* @param IOInterface $io
* The I/O service.
*/
private function addTufValidationToRepositories(Composer $composer, RepositoryManager $manager, IOInterface $io): void
{
foreach ($composer->getRepositoryManager()->getRepositories() as $repository) {
Expand All @@ -55,14 +157,35 @@ private function addTufValidationToRepositories(Composer $composer, RepositoryMa
*/
public function uninstall(Composer $composer, IOInterface $io)
{
// TODO: Implement uninstall() method.
$path = static::getStoragePath($composer->getConfig());
$io->info("Deleting TUF data in $path");

$fs = new Filesystem();
$fs->removeDirectoryPhp($path);
}

/**
* Returns the base path where TUF data will be persisted.
*
* @param Config $config
* The Composer configuration.
*
* @return string
* The base path where TUF data will be persisted.
*/
public static function getStoragePath(Config $config): string
{
return implode(DIRECTORY_SEPARATOR, [
rtrim($config->get('vendor-dir'), DIRECTORY_SEPARATOR),
'composer',
'tuf',
]);
}

/**
* {@inheritDoc}
*/
public function deactivate(Composer $composer, IOInterface $io)
{
// TODO: Implement deactivate() method.
}
}
99 changes: 0 additions & 99 deletions src/Repository/TufValidatedComposerRepository.php

This file was deleted.

Loading