guzzleClient = new Client(); } public function GetLatestDigestOfTag(string $name, string $tag): ?string { $cacheKey = 'ghcr-manifest-' . $name . $tag; $cachedVersion = apcu_fetch($cacheKey); if ($cachedVersion !== false && is_string($cachedVersion)) { return $cachedVersion; } // If one of the links below should ever become outdated, we can still upgrade the mastercontainer via the webinterface manually by opening '/api/docker/getwatchtower' try { $authTokenRequest = $this->guzzleClient->request( 'GET', 'https://ghcr.io/token?scope=repository:' . $name . ':pull' ); $body = $authTokenRequest->getBody()->getContents(); $decodedBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR); if (isset($decodedBody['token'])) { $authToken = $decodedBody['token']; $manifestRequest = $this->guzzleClient->request( 'HEAD', 'https://ghcr.io/v2/' . $name . '/manifests/' . $tag, [ 'headers' => [ 'Accept' => 'application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.docker.distribution.manifest.v2+json', 'Authorization' => 'Bearer ' . $authToken, ], ] ); $responseHeaders = $manifestRequest->getHeader('docker-content-digest'); if (count($responseHeaders) === 1) { $latestVersion = $responseHeaders[0]; apcu_add($cacheKey, $latestVersion, 600); return $latestVersion; } } error_log('Could not get digest of container ' . $name . ':' . $tag); return null; } catch (\Exception $e) { error_log('Could not get digest of container ' . $name . ':' . $tag . ' ' . $e->getMessage()); return null; } } }