Fixes#5659
- Automatically switch off plugins by default in July 2022
- reword hash into object in schema
Co-authored-by: Nils Adermann <naderman@naderman.de>
"description":"This is a hash of package name (keys) and version constraints (values) that are required to run this package.",
"description":"This is an object of package name (keys) and version constraints (values) that are required to run this package.",
"additionalProperties":{
"type":"string"
}
},
"require-dev":{
"type":"object",
"description":"This is a hash of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).",
"description":"This is an object of package name (keys) and version constraints (values) that this package requires for developing it (testing tools and such).",
"additionalProperties":{
"type":"string"
}
},
"replace":{
"type":"object",
"description":"This is a hash of package name (keys) and version constraints (values) that can be replaced by this package.",
"description":"This is an object of package name (keys) and version constraints (values) that can be replaced by this package.",
"additionalProperties":{
"type":"string"
}
},
"conflict":{
"type":"object",
"description":"This is a hash of package name (keys) and version constraints (values) that conflict with this package.",
"description":"This is an object of package name (keys) and version constraints (values) that conflict with this package.",
"additionalProperties":{
"type":"string"
}
},
"provide":{
"type":"object",
"description":"This is a hash of package name (keys) and version constraints (values) that this package provides in addition to this package's name.",
"description":"This is an object of package name (keys) and version constraints (values) that this package provides in addition to this package's name.",
"additionalProperties":{
"type":"string"
}
},
"suggest":{
"type":"object",
"description":"This is a hash of package name (keys) and descriptions (values) that this package suggests work well with it (this will be suggested to the user during installation).",
"description":"This is an object of package name (keys) and descriptions (values) that this package suggests work well with it (this will be suggested to the user during installation).",
"additionalProperties":{
"type":"string"
}
@ -217,7 +217,7 @@
"properties":{
"psr-0":{
"type":"object",
"description":"This is a hash of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.",
"description":"This is an object of namespaces (keys) and the directories they can be found into (values, can be arrays of paths) by the autoloader.",
"additionalProperties":{
"type":["string","array"],
"items":{
@ -227,7 +227,7 @@
},
"psr-4":{
"type":"object",
"description":"This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
"description":"This is an object of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
"additionalProperties":{
"type":["string","array"],
"items":{
@ -283,11 +283,18 @@
"properties":{
"platform":{
"type":"object",
"description":"This is a hash of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
"description":"This is an object of package name (keys) and version (values) that will be used to mock the platform packages on this machine.",
"additionalProperties":{
"type":["string","boolean"]
}
},
"allow-plugins":{
"type":["object","boolean"],
"description":"This is an object of {\"pattern\": true|false} with packages which are allowed to be loaded as plugins, or true to allow all, false to allow none. Defaults to {} which prompts when an unknown plugin is added.",
"additionalProperties":{
"type":["boolean"]
}
},
"process-timeout":{
"type":"integer",
"description":"The timeout in seconds for process executions, defaults to 300 (5mins)."
@ -302,7 +309,10 @@
},
"preferred-install":{
"type":["string","object"],
"description":"The install method Composer will prefer to use, defaults to auto and can be any of source, dist, auto, or a hash of {\"pattern\": \"preference\"}."
"description":"The install method Composer will prefer to use, defaults to auto and can be any of source, dist, auto, or an object of {\"pattern\": \"preference\"}.",
"additionalProperties":{
"type":["string"]
}
},
"notify-on-install":{
"type":"boolean",
@ -317,21 +327,21 @@
},
"github-oauth":{
"type":"object",
"description":"A hash of domain name => github API oauth tokens, typically {\"github.com\":\"<token>\"}.",
"description":"An object of domain name => github API oauth tokens, typically {\"github.com\":\"<token>\"}.",
"additionalProperties":{
"type":"string"
}
},
"gitlab-oauth":{
"type":"object",
"description":"A hash of domain name => gitlab API oauth tokens, typically {\"gitlab.com\":\"<token>\"}.",
"description":"An object of domain name => gitlab API oauth tokens, typically {\"gitlab.com\":\"<token>\"}.",
"additionalProperties":{
"type":"string"
}
},
"gitlab-token":{
"type":"object",
"description":"A hash of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}.",
"description":"An object of domain name => gitlab private tokens, typically {\"gitlab.com\":\"<token>\"}.",
"additionalProperties":{
"type":"string"
}
@ -342,7 +352,7 @@
},
"bearer":{
"type":"object",
"description":"A hash of domain name => bearer authentication token, for example {\"example.com\":\"<token>\"}.",
"description":"An object of domain name => bearer authentication token, for example {\"example.com\":\"<token>\"}.",
"additionalProperties":{
"type":"string"
}
@ -372,7 +382,7 @@
},
"http-basic":{
"type":"object",
"description":"A hash of domain name => {\"username\": \"...\", \"password\": \"...\"}.",
"description":"An object of domain name => {\"username\": \"...\", \"password\": \"...\"}.",
"additionalProperties":{
"type":"object",
"required":["username","password"],
@ -631,7 +641,7 @@
"properties":{
"psr-0":{
"type":"object",
"description":"This is a hash of namespaces (keys) and the directories they can be found in (values, can be arrays of paths) by the autoloader.",
"description":"This is an object of namespaces (keys) and the directories they can be found in (values, can be arrays of paths) by the autoloader.",
"additionalProperties":{
"type":["string","array"],
"items":{
@ -641,7 +651,7 @@
},
"psr-4":{
"type":"object",
"description":"This is a hash of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
"description":"This is an object of namespaces (keys) and the PSR-4 directories they can map to (values, can be arrays of paths) by the autoloader.",
throw new \RuntimeException('Failed to update composer.json with a valid format, reverting to the original content. Please report an issue to us with details (command you run and a copy of your composer.json).', 0, $e);
throw new \RuntimeException('Failed to update composer.json with a valid format, reverting to the original content. Please report an issue to us with details (command you run and a copy of your composer.json).'.PHP_EOL.implode(PHP_EOL, $e->getErrors()), 0, $e);
if (!$this->isPluginAllowed($package->getName(), $isGlobalPlugin)) {
$this->io->writeError('Skipped loading "'.$package->getName() . '" '.($isGlobalPlugin ? '(installed globally) ' : '').'as it is not in config.allow-plugins', true, IOInterface::DEBUG);
return;
}
if ($package->getType() === 'composer-plugin') {
$requiresComposer = null;
foreach ($package->getRequires() as $link) { /** @var Link $link */
$rootPackageRepo = new RootPackageRepository($rootPackage);
@ -357,6 +376,13 @@ class PluginManager
*/
public function addPlugin(PluginInterface $plugin, $isGlobalPlugin = false, PackageInterface $sourcePackage = null)
{
if ($sourcePackage === null) {
trigger_error('Calling PluginManager::addPlugin without $sourcePackage is deprecated, if you are using this please get in touch with us to explain the use case', E_USER_DEPRECATED);
$this->io->writeError('Skipped loading "'.get_class($plugin).' from '.$sourcePackage->getName() . '" '.($isGlobalPlugin ? '(installed globally) ' : '').' as it is not in config.allow-plugins', true, IOInterface::DEBUG);
$this->io->writeError('<warning>For additional security you should declare the allow-plugins config with a list of packages names that are allowed to run code. See https://getcomposer.org/allow-plugins</warning>');
$this->io->writeError('<warning>You have until July 2022 to add the setting. Composer will then switch the default behavior to disallow all plugins.</warning>');
$warned['all'] = true;
}
// if no config is defined we allow all plugins for BC
$this->io->writeError('<warning>'.$package.($isGlobalPlugin ? ' (installed globally)' : '').' contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins</warning>');
while (true) {
switch ($answer = $this->io->ask('<warning>Do you trust "'.$package.'" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]</warning> ', '?')) {
case 'y':
case 'n':
case 'd':
$allow = $answer === 'y';
// persist answer in current rules to avoid prompting again if the package gets reloaded
'y - add package to allow-plugins in composer.json and let it run immediately',
'n - add package (as disallowed) to allow-plugins in composer.json to suppress further prompts',
'd - discard this, do not change composer.json and do not allow the plugin to run',
'? - print help'
));
break;
}
}
} else {
$this->io->writeError('<warning>'.$package.($isGlobalPlugin ? ' (installed globally)' : '').' contains a Composer plugin which is blocked by your allow-plugins config. You may add it to the list if you consider it safe. See https://getcomposer.org/allow-plugins</warning>');
$this->io->writeError('<warning>You can run "composer '.($isGlobalPlugin ? 'global ' : '').'config --no-plugins allow-plugins.'.$package.' [true|false]" to enable it (true) or keep it disabled and suppress this warning (false)</warning>');