Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion packages/cli/src/lib/api/issues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from "../custom-ca.js";
import { applyCustomHeaders } from "../custom-headers.js";
import { ApiError, ValidationError } from "../errors.js";
import { logger } from "../logger.js";
import { resolveOrgRegion } from "../region.js";
import { invalidateCachedResponsesMatching } from "../response-cache.js";
import { getApiBaseUrl } from "../sentry-client.js";
Expand All @@ -31,6 +32,8 @@ import {
unwrapPaginatedResult,
} from "./infrastructure.js";

const log = logger.withTag("api.issues");

const TRAILING_SLASH_RE = /\/$/;

/**
Expand Down Expand Up @@ -745,5 +748,28 @@ export async function getSharedIssue(
);
}

return (await response.json()) as { groupID: string };
let json: unknown;
try {
json = await response.json();
} catch (err) {
log.debug("Failed to parse shared issue JSON", err);
throw new ApiError(
"Share link returned invalid JSON",
response.status,
undefined,
`shared/issues/${shareId}`
);
}

const result = json as Record<string, unknown>;
if (typeof result?.groupID !== "string" || !result.groupID) {
throw new ApiError(
"Share link response missing groupID",
response.status,
"The share link returned an unexpected response shape.",
`shared/issues/${shareId}`
);
}

return { groupID: result.groupID };
}
24 changes: 23 additions & 1 deletion packages/cli/src/lib/ghcr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import { getUserAgent } from "./constants.js";
import { customFetch } from "./custom-ca.js";
import { UpgradeError } from "./errors.js";
import { logger } from "./logger.js";

const log = logger.withTag("ghcr");

/** Default timeout for GHCR HTTP requests (10 seconds) */
const GHCR_REQUEST_TIMEOUT = 10_000;
Expand Down Expand Up @@ -250,7 +253,26 @@
);
}

return (await response.json()) as OciManifest;
let json: unknown;
try {
json = await response.json();
} catch (err) {
log.debug("Failed to parse manifest JSON", err);
throw new UpgradeError(
"network_error",
`Manifest for tag "${tag}" returned invalid JSON`
);
}

const manifest = json as OciManifest;
if (!Array.isArray(manifest?.layers)) {
throw new UpgradeError(

Check failure on line 269 in packages/cli/src/lib/ghcr.ts

View workflow job for this annotation

GitHub Actions / Unit Tests

test/lib/upgrade.test.ts > fetchLatestVersion > uses GHCR manifest when channel is nightly (npm method)

UpgradeError: Manifest for tag "nightly" has no layers array ❯ fetchManifest src/lib/ghcr.ts:269:11 ❯ fetchNightlyManifest src/lib/ghcr.ts:290:10 ❯ fetchLatestNightlyVersion src/lib/upgrade.ts:460:20 ❯ test/lib/upgrade.test.ts:528:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { exitCode: 50, reason: 'network_error', format: 'Function<format>' }

Check failure on line 269 in packages/cli/src/lib/ghcr.ts

View workflow job for this annotation

GitHub Actions / Unit Tests

test/lib/upgrade.test.ts > fetchLatestVersion > uses GHCR manifest when channel is nightly (curl method)

UpgradeError: Manifest for tag "nightly" has no layers array ❯ fetchManifest src/lib/ghcr.ts:269:11 ❯ fetchNightlyManifest src/lib/ghcr.ts:290:10 ❯ fetchLatestNightlyVersion src/lib/upgrade.ts:460:20 ❯ test/lib/upgrade.test.ts:506:21 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Serialized Error: { exitCode: 50, reason: 'network_error', format: 'Function<format>' }
"network_error",
`Manifest for tag "${tag}" has no layers array`
);
}

return manifest;
}

/**
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/src/lib/hex-id-recovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,10 @@ const eventAdapter: FuzzyLookupAdapter = async (ctx) => {
statsPeriod: ctx.period ?? SCAN_PERIODS.event,
sort: "date",
});
if (!Array.isArray(data)) {
log.debug("listTransactions returned non-array data", typeof data);
return [];
}
return (data as TransactionListItem[]).map((t) => t.id);
};

Expand All @@ -469,6 +473,10 @@ const traceAdapter: FuzzyLookupAdapter = async (ctx) => {
statsPeriod: ctx.period ?? SCAN_PERIODS.trace,
sort: "date",
});
if (!Array.isArray(data)) {
log.debug("listSpans (trace) returned non-array data", typeof data);
return [];
}
return (data as SpanListItem[]).map((s) => s.trace);
};

Expand All @@ -494,6 +502,10 @@ const spanAdapter: FuzzyLookupAdapter = async (ctx) => {
statsPeriod: ctx.period ?? SCAN_PERIODS.span,
sort: "date",
});
if (!Array.isArray(data)) {
log.debug("listSpans (span) returned non-array data", typeof data);
return [];
}
return (data as SpanListItem[]).map((s) => s.id);
};

Expand Down
Loading