Fix push/pull scopes

This commit is contained in:
f-trycua
2025-04-24 23:00:26 -07:00
parent d121dc117f
commit 35e24a9d63

View File

@@ -33,6 +33,7 @@ enum PushError: Error {
case missingPart(Int) // Added for sparse file handling
case layerDownloadFailed(String) // Added for download retries
case manifestFetchFailed // Added for manifest fetching
case insufficientPermissions(String) // Added for permission issues
}
// Define a specific error type for when no underlying error exists
@@ -1694,7 +1695,7 @@ class ImageContainerRegistry: @unchecked Sendable {
Logger.info("Cache copy complete")
}
private func getToken(repository: String, scopes: [String] = ["pull", "push"]) async throws
private func getToken(repository: String, scopes: [String] = ["pull"]) async throws
-> String
{
let encodedRepo = repository.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
@@ -1702,6 +1703,8 @@ class ImageContainerRegistry: @unchecked Sendable {
// Build scope string from scopes array
let scopeString = scopes.joined(separator: ",")
Logger.info("Requesting token with scopes: \(scopeString) for repository: \(repository)")
let url = URL(
string:
"https://\(self.registry)/token?scope=repository:\(encodedRepo):\(scopeString)&service=\(self.registry)"
@@ -1719,9 +1722,29 @@ class ImageContainerRegistry: @unchecked Sendable {
if httpResponse.statusCode == 403 && scopes.contains("push")
&& scopes.contains("pull")
{
Logger.info("Permission denied for push scope, retrying with pull scope only")
return try await getToken(repository: repository, scopes: ["pull"])
}
// Check for authentication issues with better logging
if httpResponse.statusCode == 401 {
// Try to parse the error message from the response
let errorResponse =
try? JSONSerialization.jsonObject(with: data) as? [String: Any]
let errors = errorResponse?["errors"] as? [[String: Any]]
let errorMessage =
errors?.first?["message"] as? String ?? "Unknown authentication error"
Logger.error("Authentication failed: \(errorMessage)")
Logger.error(
"Make sure GITHUB_USERNAME and GITHUB_TOKEN environment variables are set correctly"
)
Logger.error(
"Your token must have 'packages:read' and 'packages:write' permissions")
throw PushError.insufficientPermissions(errorMessage)
}
// For pull scope only, if authentication fails, assume this is a public image
// and continue without a token (empty string)
if scopes == ["pull"] {
@@ -2529,6 +2552,21 @@ class ImageContainerRegistry: @unchecked Sendable {
"reassemble": "\(reassemble)",
])
// Check for credentials if not in dry-run mode
if !dryRun {
let (username, token) = getCredentialsFromEnvironment()
if username == nil || token == nil {
Logger.error(
"Missing GitHub credentials. Please set GITHUB_USERNAME and GITHUB_TOKEN environment variables"
)
Logger.error(
"Your token must have 'packages:read' and 'packages:write' permissions")
throw PushError.authenticationFailed
}
Logger.info("Using GitHub credentials from environment variables")
}
// Remove tag parsing here, imageName is now passed directly
// let components = image.split(separator: ":") ...
// let imageTag = String(tag)
@@ -2537,7 +2575,9 @@ class ImageContainerRegistry: @unchecked Sendable {
var token: String = ""
if !dryRun {
Logger.info("Getting registry authentication token")
token = try await getToken(repository: "\(self.organization)/\(imageName)")
token = try await getToken(
repository: "\(self.organization)/\(imageName)",
scopes: ["pull", "push"]) // Explicitly specify both pull and push scopes
} else {
Logger.info("Dry run mode: skipping authentication token request")
}