From 177a981848e3e3c4a45257146a7202628decf1de Mon Sep 17 00:00:00 2001 From: Tiago Noronha Date: Wed, 26 Jan 2022 15:23:51 +0000 Subject: [PATCH] Adds rotate github secrets command --- load-application.php | 1 + src/commands/rotate-github-secrets.php | 138 +++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 src/commands/rotate-github-secrets.php diff --git a/load-application.php b/load-application.php index 7144fdad..da5a8f38 100644 --- a/load-application.php +++ b/load-application.php @@ -26,5 +26,6 @@ $application->add( new Team51\Command\Front_List_Exports() ); $application->add( new Team51\Command\Get_PHP_Errors() ); $application->add( new Team51\Command\Remove_User() ); +$application->add( new Team51\Command\Rotate_GitHub_Secrets() ); $application->run(); diff --git a/src/commands/rotate-github-secrets.php b/src/commands/rotate-github-secrets.php new file mode 100644 index 00000000..eb73f880 --- /dev/null +++ b/src/commands/rotate-github-secrets.php @@ -0,0 +1,138 @@ +setDescription( 'Updates GitHub secrets across all site repositories within the GITHUB_API_OWNER organization.' ) + ->setHelp( 'This command allows you to bulk-update GitHub secrets.' ); + } + + protected function execute( InputInterface $input, OutputInterface $output ) { + $api_helper = new API_Helper(); + + $mappings = array(); + + $output->writeln( 'Getting data from DeployHQ.' ); + + $projects = $api_helper->call_deploy_hq_api( 'projects', 'GET', array() ); + + if ( empty( $projects ) ) { + $output->writeln( 'Failed to get data from DeployHQ.' ); + exit; + } + + foreach ( $projects as $project ) { + $repository = false; + $sftp_username = false; + + // Get git repo name. + if ( empty( $project->repository->url ) ) { + continue; + } + + if ( ! preg_match( '/git@github.com:' . GITHUB_API_OWNER . '\/(.*).git/', $project->repository->url, $matches ) ) { + continue; + } + + $repository = $matches[1]; + + // Get SFTP username. + $servers = $api_helper->call_deploy_hq_api( "projects/{$project->name}/servers", 'GET', array() ); + + if ( empty( $servers ) ) { + continue; + } + + foreach ( $servers as $server ) { + if ( ! empty( $server->branch ) && 'trunk' === $server->branch ) { + $sftp_username = $server->username; + break; + } + } + + if ( ! empty( $repository ) && ! empty( $sftp_username ) ) { + $mappings[ $sftp_username ] = array( + 'repository' => $repository + ); + } + } + + $output->writeln( 'Getting site data from Pressable.' ); + + $sites = $api_helper->call_pressable_api( 'sites', 'GET', array() ); + + if ( 'Success' !== $sites->message || empty( $sites->data ) ) { + $output->writeln( 'Failed to get data from Pressable.' ); + exit; + } + + foreach ( $sites->data as $site ) { + + // Get SFTP accounts for this site. + $users = $api_helper->call_pressable_api( "/sites/{$site->id}/ftp", 'GET', array() ); + + if ( 'Success' !== $users->message || empty( $users->data ) ) { + continue; + } + + $sftp_username = false; + + foreach ( $users->data as $user ) { + if ( PRESSABLE_ACCOUNT_EMAIL === $user->email ) { + $sftp_username = $user->username; + break; + } + } + + if ( ! empty( $sftp_username ) && array_key_exists( $sftp_username, $mappings ) ) { + $mappings[ $sftp_username ]['site_url'] = $site->url; + } + } + + $output->writeln( 'Adding secrets to GitHub.' ); + + foreach ( $mappings as $sftp => $data ) { + $secrets = array( + 'GH_BOT_TOKEN' => GITHUB_API_TOKEN, + 'DEPLOYHQ_TOKEN' => DEPLOY_HQ_API_KEY, + 'SITE_URL_TRUNK' => $data['site_url'], + ); + + $gh_key = $api_helper->call_github_api( + sprintf( 'repos/%s/%s/actions/secrets/public-key', GITHUB_API_OWNER, $data['repository'] ), + array(), + 'GET' + ); + + if ( empty( $gh_key ) ) { + $output->writeln( "Failed to get public key for repository '{$data['repository']}, skipping'." ); + continue; + } + + foreach ( $secrets as $secret_name => $secret_value ) { + $public_key = sodium_base642bin( $gh_key->key, SODIUM_BASE64_VARIANT_ORIGINAL ); + + $secret = $api_helper->call_github_api( + sprintf( 'repos/%s/%s/actions/secrets/%s', GITHUB_API_OWNER, $data['repository'], $secret_name ), + array( + 'encrypted_value' => base64_encode( sodium_crypto_box_seal( $secret_value, $public_key ) ), + 'key_id' => $gh_key->key_id, + ), + 'PUT' + ); + } + } + + $output->writeln( "All done." ); + } +}