diff --git a/src/Command/Archive/ArchiveExportCommand.php b/src/Command/Archive/ArchiveExportCommand.php
index e3eed864e..899f4b30e 100644
--- a/src/Command/Archive/ArchiveExportCommand.php
+++ b/src/Command/Archive/ArchiveExportCommand.php
@@ -26,7 +26,8 @@ protected function configure()
->addOption('file', 'f', InputOption::VALUE_REQUIRED, 'The filename for the archive')
->addOption('exclude-services', null, InputOption::VALUE_NONE, 'Exclude services')
->addOption('exclude-mounts', null, InputOption::VALUE_NONE, 'Exclude mounts')
- ->addOption('include-variables', null, InputOption::VALUE_NONE, 'Include variables');
+ ->addOption('include-variables', null, InputOption::VALUE_NONE, 'Include variables')
+ ->addOption('include-sensitive-values', null, InputOption::VALUE_NONE, 'Include sensitive variable values');
$this->addProjectOption();
$this->addEnvironmentOption();
}
@@ -189,12 +190,31 @@ protected function execute(InputInterface $input, OutputInterface $output)
];
if ($includeVariables) {
+ $includeSensitive = $input->getOption('include-sensitive-values');
$this->stdErr->writeln('');
$this->stdErr->writeln('Copying project-level variables');
foreach ($this->getSelectedProject()->getVariables() as $var) {
$metadata['variables']['project'][$var->name] = $var->getProperties();
- if ($var->is_sensitive) {
- $this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive project-level variable %s', $var->name));
+ if ($var->is_sensitive && !$var->hasProperty('value')) {
+ if ($var->visible_runtime) {
+ if ($includeSensitive) {
+ $value = false;
+ foreach ($apps as $app) {
+ try {
+ $value = $this->fetchSensitiveValue($app->getSshUrl(), $var->name, $var->is_json);
+ } catch (\RuntimeException $e) {
+ continue;
+ }
+ break;
+ }
+ if ($value !== false) {
+ $metadata['variables']['project'][$var->name]['value'] = $value;
+ }
+ } else {
+ $this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive project-level variable %s', $var->name));
+ $this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
+ }
+ }
}
}
@@ -202,8 +222,24 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->stdErr->writeln('Copying environment-level variables');
foreach ($environment->getVariables() as $envVar) {
$metadata['variables']['environment'][$envVar->name] = $envVar->getProperties();
- if ($envVar->is_sensitive) {
- $this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive environment-level variable %s', $envVar->name));
+ if ($envVar->is_sensitive && !$envVar->hasProperty('value')) {
+ if ($includeSensitive) {
+ $value = false;
+ foreach ($apps as $app) {
+ try {
+ $value = $this->fetchSensitiveValue($app->getSshUrl(), $envVar->name, $envVar->is_json);
+ } catch (\RuntimeException $e) {
+ continue;
+ }
+ break;
+ }
+ if ($value !== false) {
+ $metadata['variables']['environment'][$envVar->name]['value'] = $value;
+ }
+ } else {
+ $this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive environment-level variable %s', $envVar->name));
+ $this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
+ }
}
}
}
@@ -302,6 +338,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
$mountService = $this->getService('mount');
/** @var \Platformsh\Cli\Service\Rsync $rsync */
$rsync = $this->getService('rsync');
+ $rsyncOptions = [
+ 'verbose' => $output->isVeryVerbose(),
+ 'quiet' => !$output->isVerbose(),
+ ];
foreach ($apps as $app) {
$sourcePaths = [];
$mounts = $mountService->normalizeMounts($app->getMounts());
@@ -319,7 +359,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->stdErr->writeln('Copying from mount ' . $path . '');
$destination = $archiveDir . '/mounts/' . trim($path, '/');
mkdir($destination, 0755, true);
- $rsync->syncDown($app->getSshUrl(), ltrim($path, '/'), $destination);
+ $rsync->syncDown($app->getSshUrl(), ltrim($path, '/'), $destination, $rsyncOptions);
$metadata['mounts'][$path] = [
'app' => $app->getName(),
'path' => 'mounts/' . trim($path, '/'),
@@ -402,4 +442,27 @@ private function getSchemas(Service $service, $relationshipName)
return $schemas;
}
+
+ /**
+ * @param string $sshUrl
+ * @param string $varName
+ * @param bool $is_json
+ *
+ * @return mixed
+ */
+ private function fetchSensitiveValue($sshUrl, $varName, $is_json)
+ {
+ /** @var \Platformsh\Cli\Service\RemoteEnvVars $remoteEnvVars */
+ $remoteEnvVars = $this->getService('remote_env_vars');
+ if (substr($varName, 0, 4) === 'env:') {
+ return $remoteEnvVars->getEnvVar(substr($varName, 4), $sshUrl, true, 3600, false);
+ }
+
+ $variables = $remoteEnvVars->getArrayEnvVar('VARIABLES', $sshUrl);
+ if (array_key_exists($varName, $variables)) {
+ return $is_json ? json_encode($variables[$varName]) : $variables[$varName];
+ }
+
+ throw new \RuntimeException('Variable not found: ' . $varName);
+ }
}
diff --git a/src/Command/Archive/ArchiveImportCommand.php b/src/Command/Archive/ArchiveImportCommand.php
index 06c4895ae..6dd3581ea 100644
--- a/src/Command/Archive/ArchiveImportCommand.php
+++ b/src/Command/Archive/ArchiveImportCommand.php
@@ -120,12 +120,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->stdErr->writeln('Importing environment-level variables');
foreach ($metadata['variables']['environment'] as $name => $var) {
- if ($var['is_sensitive']) {
- $this->stdErr->writeln(' Skipping sensitive variable ' . $name . '');
- continue;
- }
$this->stdErr->writeln(' Processing variable ' . $name . '');
if (!array_key_exists('value', $var)) {
+ if ($var['is_sensitive']) {
+ $this->stdErr->writeln(' Skipping sensitive variable ' . $name . '');
+ continue;
+ }
$this->stdErr->writeln(' Error: no variable value found.');
continue;
}
@@ -158,12 +158,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->stdErr->writeln('Importing project-level variables');
foreach ($metadata['variables']['project'] as $name => $var) {
- if ($var['is_sensitive']) {
- $this->stdErr->writeln(' Skipping sensitive variable ' . $name . '');
- continue;
- }
$this->stdErr->writeln(' Processing variable ' . $name . '');
if (!array_key_exists('value', $var)) {
+ if ($var['is_sensitive']) {
+ $this->stdErr->writeln(' Skipping sensitive variable ' . $name . '');
+ continue;
+ }
$this->stdErr->writeln(' Error: no variable value found.');
continue;
}
diff --git a/src/Service/RemoteEnvVars.php b/src/Service/RemoteEnvVars.php
index d34b493b7..6a71cafe2 100644
--- a/src/Service/RemoteEnvVars.php
+++ b/src/Service/RemoteEnvVars.php
@@ -38,15 +38,16 @@ public function __construct(Ssh $ssh, CacheProvider $cache, Shell $shellHelper,
* @param string $sshUrl The SSH URL to the application.
* @param bool $refresh Whether to refresh the cache.
* @param int $ttl The cache lifetime of the result.
+ * @param bool $prefix Whether to prepend the service.env_prefix.
*
* @throws \Symfony\Component\Process\Exception\RuntimeException
* If the SSH command fails.
*
* @return string The environment variable or an empty string.
*/
- public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600)
+ public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600, $prefix = true)
{
- $varName = $this->config->get('service.env_prefix') . $variable;
+ $varName = $prefix ? $this->config->get('service.env_prefix') . $variable : $variable;
$cacheKey = 'env-' . $sshUrl . '-' . $varName;
$cached = $this->cache->fetch($cacheKey);
if ($refresh || $cached === false) {
@@ -69,12 +70,14 @@ public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600)
* @param string $variable
* @param string $sshUrl
* @param bool $refresh
+ * @param int $ttl
+ * @param bool $prefix
*
* @return array
*/
- public function getArrayEnvVar($variable, $sshUrl, $refresh = false)
+ public function getArrayEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600, $prefix = true)
{
- $value = $this->getEnvVar($variable, $sshUrl, $refresh);
+ $value = $this->getEnvVar($variable, $sshUrl, $refresh, $ttl, $prefix);
return json_decode(base64_decode($value), true) ?: [];
}