From a3c39576df938c6b769f6cff51e2e8123f2a8452 Mon Sep 17 00:00:00 2001 From: Luther Monson Date: Tue, 19 May 2026 21:23:43 -0700 Subject: [PATCH] filter secrets at logger callback; register basic-auth encoded blob --- .../Downloader/Type/GitHubTokenSetupTrait.php | 5 +- src/bootstrap.php | 17 +++ tests/GlobalsFunctionsTest.php | 104 ++++++++++++++++++ 3 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 tests/GlobalsFunctionsTest.php diff --git a/src/StaticPHP/Artifact/Downloader/Type/GitHubTokenSetupTrait.php b/src/StaticPHP/Artifact/Downloader/Type/GitHubTokenSetupTrait.php index 34e350d4..412a4c1c 100644 --- a/src/StaticPHP/Artifact/Downloader/Type/GitHubTokenSetupTrait.php +++ b/src/StaticPHP/Artifact/Downloader/Type/GitHubTokenSetupTrait.php @@ -16,8 +16,9 @@ trait GitHubTokenSetupTrait // GITHUB_TOKEN support if (($token = getenv('GITHUB_TOKEN')) !== false && ($user = getenv('GITHUB_USER')) !== false) { logger()->debug("Using 'GITHUB_TOKEN' with user {$user} for authentication"); - spc_add_log_filter([$user, $token]); - return ['Authorization: Basic ' . base64_encode("{$user}:{$token}")]; + $encoded = base64_encode("{$user}:{$token}"); + spc_add_log_filter([$user, $token, $encoded]); + return ["Authorization: Basic {$encoded}"]; } if (($token = getenv('GITHUB_TOKEN')) !== false) { logger()->debug("Using 'GITHUB_TOKEN' for authentication"); diff --git a/src/bootstrap.php b/src/bootstrap.php index 4e640fea..c300e1f6 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -33,6 +33,23 @@ ConsoleLogger::$date_format = 'H:i:s'; ConsoleLogger::$format = '[%date% %level_long%] %body%'; $ob_logger = new ConsoleLogger(LogLevel::WARNING); +$ob_logger->addLogCallback(function ($level, &$output, &$message, &$context, bool $shouldLog) { + global $spc_log_filters; + if (!is_array($spc_log_filters)) { + $spc_log_filters = []; + } + // filter message and context + $output = str_replace($spc_log_filters, '***', $output); + $message = str_replace($spc_log_filters, '***', $message); + $context = array_map(function ($item) use ($spc_log_filters) { + if (is_string($item)) { + return str_replace($spc_log_filters, '***', $item); + } + return $item; + }, $context); + return true; +}); + // setup log file if (filter_var(getenv('SPC_ENABLE_LOG_FILE'), FILTER_VALIDATE_BOOLEAN)) { // init spc log files diff --git a/tests/GlobalsFunctionsTest.php b/tests/GlobalsFunctionsTest.php new file mode 100644 index 00000000..b1b047db --- /dev/null +++ b/tests/GlobalsFunctionsTest.php @@ -0,0 +1,104 @@ +assertSame(['secret-value', 'other'], $GLOBALS['spc_log_filters']); + } + + public function testWriteLogMasksRegisteredValues(): void + { + spc_add_log_filter(['octocat', 'ghp_abcdef1234567890']); + + $stream = fopen('php://memory', 'r+'); + spc_write_log($stream, 'user=octocat token=ghp_abcdef1234567890'); + rewind($stream); + $written = stream_get_contents($stream); + fclose($stream); + + $this->assertSame('user=*** token=***', $written); + } + + public function testLoggerCallbackMasksOutput(): void + { + $token = 'ghp_abcdef1234567890'; + spc_add_log_filter($token); + + $stream = fopen('php://memory', 'r+'); + $logger = new ConsoleLogger(LogLevel::DEBUG, $stream, false); + $logger->addLogCallback(function ($level, &$output, &$message, &$context, bool $shouldLog) { + global $spc_log_filters; + if (!is_array($spc_log_filters)) { + $spc_log_filters = []; + } + $output = str_replace($spc_log_filters, '***', $output); + $message = str_replace($spc_log_filters, '***', $message); + $context = array_map(function ($item) use ($spc_log_filters) { + if (is_string($item)) { + return str_replace($spc_log_filters, '***', $item); + } + return $item; + }, $context); + return true; + }); + + $logger->debug("[PASSTHRU] curl -H\"Authorization: Bearer {$token}\" https://api.github.com/x"); + + rewind($stream); + $written = stream_get_contents($stream); + fclose($stream); + + $this->assertStringNotContainsString($token, $written); + $this->assertStringContainsString('***', $written); + } + + public function testGitHubTokenTraitRegistersEncodedBasicAuthBlob(): void + { + $user = 'octocat'; + $token = 'ghp_abcdef1234567890'; + $original_token = getenv('GITHUB_TOKEN'); + $original_user = getenv('GITHUB_USER'); + + putenv("GITHUB_TOKEN={$token}"); + putenv("GITHUB_USER={$user}"); + + try { + $headers = \StaticPHP\Artifact\Downloader\Type\GitHubRelease::getGitHubTokenHeadersStatic(); + + $encoded = base64_encode("{$user}:{$token}"); + $this->assertSame(["Authorization: Basic {$encoded}"], $headers); + $this->assertContains($user, $GLOBALS['spc_log_filters']); + $this->assertContains($token, $GLOBALS['spc_log_filters']); + $this->assertContains($encoded, $GLOBALS['spc_log_filters']); + } finally { + $original_token === false ? putenv('GITHUB_TOKEN') : putenv("GITHUB_TOKEN={$original_token}"); + $original_user === false ? putenv('GITHUB_USER') : putenv("GITHUB_USER={$original_user}"); + } + } +}