propagate token issues
All checks were successful
Build and Release / build (push) Successful in 2m13s
Build and Release / sign (push) Successful in 1m33s

This commit is contained in:
Emil Lerch 2025-07-20 13:55:49 -07:00
parent 6ad55474fa
commit e2199c2636
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 92 additions and 8 deletions

View file

@ -100,7 +100,21 @@ fn getStarredProjects(allocator: Allocator, client: *http.Client, token: []const
try req.wait(); try req.wait();
if (req.response.status != .ok) { if (req.response.status != .ok) {
return error.HttpRequestFailed; const stderr = std.io.getStdErr().writer();
switch (req.response.status) {
.unauthorized => {
stderr.print("GitLab API: Authentication failed - invalid or missing token (HTTP 401)\n", .{}) catch {};
return error.Unauthorized;
},
.forbidden => {
stderr.print("GitLab API: Access forbidden - token may lack required permissions (HTTP 403)\n", .{}) catch {};
return error.Forbidden;
},
else => {
stderr.print("GitLab API request failed with status: {} (HTTP {})\n", .{ req.response.status, @intFromEnum(req.response.status) }) catch {};
return error.HttpRequestFailed;
},
}
} }
const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024); const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024);
@ -159,9 +173,21 @@ fn getCurrentUsername(allocator: Allocator, client: *http.Client, token: []const
try req.wait(); try req.wait();
if (req.response.status != .ok) { if (req.response.status != .ok) {
// If we can't get user info, fall back to hardcoded username const stderr = std.io.getStdErr().writer();
// This is a workaround for tokens with limited scopes switch (req.response.status) {
return try allocator.dupe(u8, "elerch"); .unauthorized => {
stderr.print("GitLab API: Authentication failed - invalid or missing token (HTTP 401)\n", .{}) catch {};
return error.Unauthorized;
},
.forbidden => {
stderr.print("GitLab API: Access forbidden - token may lack required permissions (HTTP 403)\n", .{}) catch {};
return error.Forbidden;
},
else => {
stderr.print("GitLab API request failed with status: {} (HTTP {})\n", .{ req.response.status, @intFromEnum(req.response.status) }) catch {};
return error.HttpRequestFailed;
},
}
} }
const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024); const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024);
@ -205,7 +231,21 @@ fn getProjectReleases(allocator: Allocator, client: *http.Client, token: []const
try req.wait(); try req.wait();
if (req.response.status != .ok) { if (req.response.status != .ok) {
return error.HttpRequestFailed; const stderr = std.io.getStdErr().writer();
switch (req.response.status) {
.unauthorized => {
stderr.print("GitLab API: Authentication failed - invalid or missing token (HTTP 401)\n", .{}) catch {};
return error.Unauthorized;
},
.forbidden => {
stderr.print("GitLab API: Access forbidden - token may lack required permissions (HTTP 403)\n", .{}) catch {};
return error.Forbidden;
},
else => {
stderr.print("GitLab API request failed with status: {} (HTTP {})\n", .{ req.response.status, @intFromEnum(req.response.status) }) catch {};
return error.HttpRequestFailed;
},
}
} }
const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024); const body = try req.reader().readAllAlloc(allocator, 10 * 1024 * 1024);
@ -258,7 +298,7 @@ test "gitlab provider" {
// Test with empty token (should fail gracefully) // Test with empty token (should fail gracefully)
const releases = gitlab_provider.fetchReleases(allocator) catch |err| { const releases = gitlab_provider.fetchReleases(allocator) catch |err| {
try std.testing.expect(err == error.HttpRequestFailed); try std.testing.expect(err == error.Unauthorized or err == error.HttpRequestFailed);
return; return;
}; };
defer { defer {

View file

@ -93,6 +93,10 @@ fn fetchReleasesMultiRepo(allocator: Allocator, client: *http.Client, token: []c
const all_tag_data = getAllReferencesMultiRepo(allocator, client, token, parsed_repos.items) catch |err| { const all_tag_data = getAllReferencesMultiRepo(allocator, client, token, parsed_repos.items) catch |err| {
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
stderr.print("Failed to get references: {}\n", .{err}) catch {}; stderr.print("Failed to get references: {}\n", .{err}) catch {};
// Propagate authentication and other critical errors instead of silently returning empty results
if (err == error.HttpRequestFailed) {
return err;
}
return releases; return releases;
}; };
defer { defer {
@ -113,6 +117,10 @@ fn fetchReleasesMultiRepo(allocator: Allocator, client: *http.Client, token: []c
const commit_dates = getAllCommitDatesMultiRepo(allocator, client, token, parsed_repos.items, all_tag_data.items) catch |err| { const commit_dates = getAllCommitDatesMultiRepo(allocator, client, token, parsed_repos.items, all_tag_data.items) catch |err| {
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
stderr.print("Failed to get commit dates: {}\n", .{err}) catch {}; stderr.print("Failed to get commit dates: {}\n", .{err}) catch {};
// Propagate authentication and other critical errors instead of silently returning empty results
if (err == error.HttpRequestFailed) {
return err;
}
return releases; return releases;
}; };
defer { defer {
@ -264,12 +272,25 @@ fn getAllReferencesMultiRepo(allocator: Allocator, client: *http.Client, token:
if (root.object.get("errors")) |errors| { if (root.object.get("errors")) |errors| {
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
stderr.print("GraphQL errors in references query: ", .{}) catch {}; stderr.print("GraphQL errors in references query: ", .{}) catch {};
var has_auth_error = false;
for (errors.array.items) |error_item| { for (errors.array.items) |error_item| {
if (error_item.object.get("message")) |message| { if (error_item.object.get("message")) |message| {
stderr.print("{s} ", .{message.string}) catch {}; stderr.print("{s} ", .{message.string}) catch {};
// Check for authentication-related error messages
if (std.mem.indexOf(u8, message.string, "authentication") != null or
std.mem.indexOf(u8, message.string, "unauthorized") != null or
std.mem.indexOf(u8, message.string, "invalid token") != null or
std.mem.indexOf(u8, message.string, "access denied") != null)
{
has_auth_error = true;
}
} }
} }
stderr.print("\n", .{}) catch {}; stderr.print("\n", .{}) catch {};
// Propagate authentication errors instead of returning empty results
if (has_auth_error) {
return error.HttpRequestFailed;
}
return all_tag_data; return all_tag_data;
} }
@ -450,13 +471,26 @@ fn getAllCommitDatesMultiRepo(allocator: Allocator, client: *http.Client, token:
if (root.object.get("errors")) |errors| { if (root.object.get("errors")) |errors| {
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
stderr.print("GraphQL errors in commit dates query: ", .{}) catch {}; stderr.print("GraphQL errors in commit dates query: ", .{}) catch {};
var has_auth_error = false;
for (errors.array.items) |error_item| { for (errors.array.items) |error_item| {
if (error_item.object.get("message")) |message| { if (error_item.object.get("message")) |message| {
stderr.print("{s} ", .{message.string}) catch {}; stderr.print("{s} ", .{message.string}) catch {};
// Check for authentication-related error messages
if (std.mem.indexOf(u8, message.string, "authentication") != null or
std.mem.indexOf(u8, message.string, "unauthorized") != null or
std.mem.indexOf(u8, message.string, "invalid token") != null or
std.mem.indexOf(u8, message.string, "access denied") != null)
{
has_auth_error = true;
}
} }
} }
stderr.print("\n", .{}) catch {}; stderr.print("\n", .{}) catch {};
// Return empty dates for all tags // Propagate authentication errors instead of returning empty results
if (has_auth_error) {
return error.HttpRequestFailed;
}
// Return empty dates for all tags for non-auth errors
for (tag_data) |_| { for (tag_data) |_| {
try commit_dates.append(""); try commit_dates.append("");
} }
@ -546,7 +580,17 @@ fn makeGraphQLRequest(allocator: Allocator, client: *http.Client, token: []const
if (req.response.status != .ok) { if (req.response.status != .ok) {
const stderr = std.io.getStdErr().writer(); const stderr = std.io.getStdErr().writer();
stderr.print("SourceHut GraphQL API request failed with status: {}\n", .{req.response.status}) catch {}; switch (req.response.status) {
.unauthorized => {
stderr.print("SourceHut GraphQL API: Authentication failed - invalid or missing token (HTTP 401)\n", .{}) catch {};
},
.forbidden => {
stderr.print("SourceHut GraphQL API: Access forbidden - token may lack required permissions (HTTP 403)\n", .{}) catch {};
},
else => {
stderr.print("SourceHut GraphQL API request failed with status: {} (HTTP {})\n", .{ req.response.status, @intFromEnum(req.response.status) }) catch {};
},
}
return error.HttpRequestFailed; return error.HttpRequestFailed;
} }