Skip to content

Commit b8bcb2f

Browse files
committed
Support exporting sensitive variables
1 parent e44020f commit b8bcb2f

File tree

3 files changed

+84
-18
lines changed

3 files changed

+84
-18
lines changed

src/Command/Archive/ArchiveExportCommand.php

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ protected function configure()
2626
->addOption('file', 'f', InputOption::VALUE_REQUIRED, 'The filename for the archive')
2727
->addOption('exclude-services', null, InputOption::VALUE_NONE, 'Exclude services')
2828
->addOption('exclude-mounts', null, InputOption::VALUE_NONE, 'Exclude mounts')
29-
->addOption('include-variables', null, InputOption::VALUE_NONE, 'Include variables');
29+
->addOption('include-variables', null, InputOption::VALUE_NONE, 'Include variables')
30+
->addOption('include-sensitive-values', null, InputOption::VALUE_NONE, 'Include sensitive variable values');
3031
$this->addProjectOption();
3132
$this->addEnvironmentOption();
3233
}
@@ -189,21 +190,56 @@ protected function execute(InputInterface $input, OutputInterface $output)
189190
];
190191

191192
if ($includeVariables) {
193+
$includeSensitive = $input->getOption('include-sensitive-values');
192194
$this->stdErr->writeln('');
193195
$this->stdErr->writeln('Copying project-level variables');
194196
foreach ($this->getSelectedProject()->getVariables() as $var) {
195197
$metadata['variables']['project'][$var->name] = $var->getProperties();
196-
if ($var->is_sensitive) {
197-
$this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive project-level variable <comment>%s</comment>', $var->name));
198+
if ($var->is_sensitive && !$var->hasProperty('value')) {
199+
if ($var->visible_runtime) {
200+
if ($includeSensitive) {
201+
$value = false;
202+
foreach ($apps as $app) {
203+
try {
204+
$value = $this->fetchSensitiveValue($app->getSshUrl(), $var->name, $var->is_json);
205+
} catch (\RuntimeException $e) {
206+
continue;
207+
}
208+
break;
209+
}
210+
if ($value !== false) {
211+
$metadata['variables']['project'][$var->name]['value'] = $value;
212+
}
213+
} else {
214+
$this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive project-level variable <comment>%s</comment>', $var->name));
215+
$this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
216+
}
217+
}
198218
}
199219
}
200220

201221
$this->stdErr->writeln('');
202222
$this->stdErr->writeln('Copying environment-level variables');
203223
foreach ($environment->getVariables() as $envVar) {
204224
$metadata['variables']['environment'][$envVar->name] = $envVar->getProperties();
205-
if ($envVar->is_sensitive) {
206-
$this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive environment-level variable <comment>%s</comment>', $envVar->name));
225+
if ($envVar->is_sensitive && !$envVar->hasProperty('value')) {
226+
if ($includeSensitive) {
227+
$value = false;
228+
foreach ($apps as $app) {
229+
try {
230+
$value = $this->fetchSensitiveValue($app->getSshUrl(), $envVar->name, $envVar->is_json);
231+
} catch (\RuntimeException $e) {
232+
continue;
233+
}
234+
break;
235+
}
236+
if ($value !== false) {
237+
$metadata['variables']['environment'][$envVar->name]['value'] = $value;
238+
}
239+
} else {
240+
$this->stdErr->writeln(sprintf(' Warning: cannot save value for sensitive environment-level variable <comment>%s</comment>', $envVar->name));
241+
$this->stdErr->writeln(' Use --include-sensitive-values to try to fetch this via SSH');
242+
}
207243
}
208244
}
209245
}
@@ -302,6 +338,10 @@ protected function execute(InputInterface $input, OutputInterface $output)
302338
$mountService = $this->getService('mount');
303339
/** @var \Platformsh\Cli\Service\Rsync $rsync */
304340
$rsync = $this->getService('rsync');
341+
$rsyncOptions = [
342+
'verbose' => $output->isVeryVerbose(),
343+
'quiet' => !$output->isVerbose(),
344+
];
305345
foreach ($apps as $app) {
306346
$sourcePaths = [];
307347
$mounts = $mountService->normalizeMounts($app->getMounts());
@@ -319,7 +359,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
319359
$this->stdErr->writeln('Copying from mount <info>' . $path . '</info>');
320360
$destination = $archiveDir . '/mounts/' . trim($path, '/');
321361
mkdir($destination, 0755, true);
322-
$rsync->syncDown($app->getSshUrl(), ltrim($path, '/'), $destination);
362+
$rsync->syncDown($app->getSshUrl(), ltrim($path, '/'), $destination, $rsyncOptions);
323363
$metadata['mounts'][$path] = [
324364
'app' => $app->getName(),
325365
'path' => 'mounts/' . trim($path, '/'),
@@ -402,4 +442,27 @@ private function getSchemas(Service $service, $relationshipName)
402442

403443
return $schemas;
404444
}
445+
446+
/**
447+
* @param string $sshUrl
448+
* @param string $varName
449+
* @param bool $is_json
450+
*
451+
* @return mixed
452+
*/
453+
private function fetchSensitiveValue($sshUrl, $varName, $is_json)
454+
{
455+
/** @var \Platformsh\Cli\Service\RemoteEnvVars $remoteEnvVars */
456+
$remoteEnvVars = $this->getService('remote_env_vars');
457+
if (substr($varName, 0, 4) === 'env:') {
458+
return $remoteEnvVars->getEnvVar(substr($varName, 4), $sshUrl, true, 3600, false);
459+
}
460+
461+
$variables = $remoteEnvVars->getArrayEnvVar('VARIABLES', $sshUrl);
462+
if (array_key_exists($varName, $variables)) {
463+
return $is_json ? json_encode($variables[$varName]) : $variables[$varName];
464+
}
465+
466+
throw new \RuntimeException('Variable not found: ' . $varName);
467+
}
405468
}

src/Command/Archive/ArchiveImportCommand.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
120120
$this->stdErr->writeln('Importing environment-level variables');
121121

122122
foreach ($metadata['variables']['environment'] as $name => $var) {
123-
if ($var['is_sensitive']) {
124-
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
125-
continue;
126-
}
127123
$this->stdErr->writeln(' Processing variable <info>' . $name . '</info>');
128124
if (!array_key_exists('value', $var)) {
125+
if ($var['is_sensitive']) {
126+
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
127+
continue;
128+
}
129129
$this->stdErr->writeln(' Error: no variable value found.');
130130
continue;
131131
}
@@ -158,12 +158,12 @@ protected function execute(InputInterface $input, OutputInterface $output)
158158
$this->stdErr->writeln('Importing project-level variables');
159159

160160
foreach ($metadata['variables']['project'] as $name => $var) {
161-
if ($var['is_sensitive']) {
162-
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
163-
continue;
164-
}
165161
$this->stdErr->writeln(' Processing variable <info>' . $name . '</info>');
166162
if (!array_key_exists('value', $var)) {
163+
if ($var['is_sensitive']) {
164+
$this->stdErr->writeln(' Skipping sensitive variable <comment>' . $name . '</comment>');
165+
continue;
166+
}
167167
$this->stdErr->writeln(' Error: no variable value found.');
168168
continue;
169169
}

src/Service/RemoteEnvVars.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,16 @@ public function __construct(Ssh $ssh, CacheProvider $cache, Shell $shellHelper,
3838
* @param string $sshUrl The SSH URL to the application.
3939
* @param bool $refresh Whether to refresh the cache.
4040
* @param int $ttl The cache lifetime of the result.
41+
* @param bool $prefix Whether to prepend the service.env_prefix.
4142
*
4243
* @throws \Symfony\Component\Process\Exception\RuntimeException
4344
* If the SSH command fails.
4445
*
4546
* @return string The environment variable or an empty string.
4647
*/
47-
public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600)
48+
public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600, $prefix = true)
4849
{
49-
$varName = $this->config->get('service.env_prefix') . $variable;
50+
$varName = $prefix ? $this->config->get('service.env_prefix') . $variable : $variable;
5051
$cacheKey = 'env-' . $sshUrl . '-' . $varName;
5152
$cached = $this->cache->fetch($cacheKey);
5253
if ($refresh || $cached === false) {
@@ -69,12 +70,14 @@ public function getEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600)
6970
* @param string $variable
7071
* @param string $sshUrl
7172
* @param bool $refresh
73+
* @param int $ttl
74+
* @param bool $prefix
7275
*
7376
* @return array
7477
*/
75-
public function getArrayEnvVar($variable, $sshUrl, $refresh = false)
78+
public function getArrayEnvVar($variable, $sshUrl, $refresh = false, $ttl = 3600, $prefix = true)
7679
{
77-
$value = $this->getEnvVar($variable, $sshUrl, $refresh);
80+
$value = $this->getEnvVar($variable, $sshUrl, $refresh, $ttl, $prefix);
7881

7982
return json_decode(base64_decode($value), true) ?: [];
8083
}

0 commit comments

Comments
 (0)