Skip to content

Commit

Permalink
Support exporting sensitive variables
Browse files Browse the repository at this point in the history
  • Loading branch information
pjcdawkins committed Jul 24, 2019
1 parent e44020f commit b8bcb2f
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 18 deletions.
75 changes: 69 additions & 6 deletions src/Command/Archive/ArchiveExportCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -189,21 +190,56 @@ 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 <comment>%s</comment>', $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 <comment>%s</comment>', $var->name));
$this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
}
}
}
}

$this->stdErr->writeln('');
$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 <comment>%s</comment>', $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 <comment>%s</comment>', $envVar->name));
$this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
}
}
}
}
Expand Down Expand Up @@ -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());
Expand All @@ -319,7 +359,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$this->stdErr->writeln('Copying from mount <info>' . $path . '</info>');
$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, '/'),
Expand Down Expand Up @@ -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);
}
}
16 changes: 8 additions & 8 deletions src/Command/Archive/ArchiveImportCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 <comment>' . $name . '</comment>');
continue;
}
$this->stdErr->writeln(' Processing variable <info>' . $name . '</info>');
if (!array_key_exists('value', $var)) {
if ($var['is_sensitive']) {
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
continue;
}
$this->stdErr->writeln(' Error: no variable value found.');
continue;
}
Expand Down Expand Up @@ -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 <comment>' . $name . '</comment>');
continue;
}
$this->stdErr->writeln(' Processing variable <info>' . $name . '</info>');
if (!array_key_exists('value', $var)) {
if ($var['is_sensitive']) {
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
continue;
}
$this->stdErr->writeln(' Error: no variable value found.');
continue;
}
Expand Down
11 changes: 7 additions & 4 deletions src/Service/RemoteEnvVars.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) ?: [];
}
Expand Down

0 comments on commit b8bcb2f

Please sign in to comment.