Skip to content

Instantly share code, notes, and snippets.

@rieschl
Created February 19, 2020 19:23
Show Gist options
  • Save rieschl/fb5a404e1521920dcbe62ec0ba1dc733 to your computer and use it in GitHub Desktop.
Save rieschl/fb5a404e1521920dcbe62ec0ba1dc733 to your computer and use it in GitHub Desktop.
Update Github Secrets on all Repos
<?php
declare(strict_types=1);
use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;
use function GuzzleHttp\Psr7\parse_header;
require 'vendor/autoload.php';
$baseUri = 'https://api.github.com/';
$ghUsername = 'user';
$ghToken = 'token';
$secrets = [
'SECRET_NAME' => 'secret value',
'SECRET_TWO' => 'even more secret',
];
$uri = $baseUri . 'orgs/eventjet/repos';
while ($uri !== null) {
[$repos, $next] = fetchRepos($uri);
if ($next === null) {
$uri = null;
} else {
$uri = $next;
}
foreach ($repos as $repo) {
echo $repo['full_name'] . "\n";
setRepositorySecrets($repo['full_name'], $secrets);
}
}
function fetchRepos(string $uri)
{
global $ghUsername, $ghToken;
$client = new Client();
$response = $client->get($uri, ['auth' => [$ghUsername, $ghToken],]);
$repos = (string)$response->getBody();
$repos = json_decode($repos, true);
$next = getNextLink($response);
return [$repos, $next];
}
function getNextLink(ResponseInterface $response): ?string
{
$link = parse_header($response->getHeader('Link'));
foreach ($link as $item) {
if ($item['rel'] === 'next') {
return substr($item[0], 1, -1);
}
}
return null;
}
/**
* @param array<string, string> $secrets
*/
function setRepositorySecrets(string $repo, array $secrets)
{
$key = fetchKey($repo);
foreach ($secrets as $secretName => $secretValue) {
setSecret($repo, $secretName, $secretValue, $key);
}
}
/**
* @param array{key: string, key_id: string} $key
*/
function setSecret(string $repo, string $secretName, string $secretValue, array $key)
{
global $baseUri, $ghUsername, $ghToken;
$client = new Client(['base_uri' => $baseUri]);
$encryptedValue = encryptSecret($key['key'], $secretValue);
$client->put(
'repos/' . $repo . '/actions/secrets/' . $secretName,
[
'auth' => [$ghUsername, $ghToken],
'json' => ['key_id' => $key['key_id'], 'encrypted_value' => $encryptedValue],
]
);
}
function encryptSecret(string $key, string $message): string
{
$binKey = base64_decode($key);
$encrypted = sodium_crypto_box_seal($message, $binKey);
return base64_encode($encrypted);
}
/**
* @return array{key: string, key_id: string}
*/
function fetchKey(string $repo): array
{
global $baseUri, $ghUsername, $ghToken;
$client = new Client(['base_uri' => $baseUri]);
$response = $client->get(
'repos/' . $repo . '/actions/secrets/public-key',
['auth' => [$ghUsername, $ghToken]]
);
return json_decode((string)$response->getBody(), true);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment