Skip to content

Commit d8e478a

Browse files
committed
fix: add type-safe post return, strip image digests consistently
1 parent b7fa420 commit d8e478a

File tree

5 files changed

+25
-18
lines changed

5 files changed

+25
-18
lines changed

apps/supervisor/src/workloadManager/compute.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
type WorkloadManagerCreateOptions,
77
type WorkloadManagerOptions,
88
} from "./types.js";
9-
import { ComputeClient } from "@internal/compute";
9+
import { ComputeClient, stripImageDigest } from "@internal/compute";
1010
import { env } from "../env.js";
1111
import { getRunnerId } from "../util.js";
1212
import { buildOtlpTracePayload } from "../otlpPayload.js";
@@ -82,7 +82,7 @@ export class ComputeWorkloadManager implements WorkloadManager {
8282
}
8383

8484
// Strip image digest - resolve by tag, not digest
85-
const imageRef = opts.image.split("@")[0]!;
85+
const imageRef = stripImageDigest(opts.image);
8686

8787
// Wide event: single canonical log line emitted in finally
8888
const event: Record<string, unknown> = {

apps/webapp/app/v3/services/computeTemplateCreation.server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ComputeClient } from "@internal/compute";
1+
import { ComputeClient, stripImageDigest } from "@internal/compute";
22
import { env } from "~/env.server";
33
import { logger } from "~/services/logger.server";
44
import type { PrismaClientOrTransaction } from "~/db.server";
@@ -159,7 +159,7 @@ export class ComputeTemplateCreationService {
159159

160160
try {
161161
await this.client.templates.create({
162-
image: imageReference,
162+
image: stripImageDigest(imageReference),
163163
cpu: 0.5,
164164
memory_mb: 512,
165165
background: options?.background,

internal-packages/compute/src/client.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class HttpTransport {
4646
return options?.signal ?? AbortSignal.timeout(this.opts.timeoutMs);
4747
}
4848

49-
async post<T = unknown>(path: string, body: unknown, options?: RequestOptions): Promise<T> {
49+
async post<T = unknown>(path: string, body: unknown, options?: RequestOptions): Promise<T | undefined> {
5050
const url = `${this.opts.gatewayUrl}${path}`;
5151

5252
const response = await fetch(url, {
@@ -63,7 +63,7 @@ class HttpTransport {
6363

6464
// 202 Accepted or 204 No Content - no body to parse
6565
if (response.status === 202 || response.status === 204) {
66-
return undefined as T;
66+
return undefined;
6767
}
6868

6969
return (await response.json()) as T;
@@ -106,17 +106,8 @@ class TemplatesNamespace {
106106
async create(
107107
req: TemplateCreateRequest,
108108
options?: RequestOptions
109-
): Promise<{ accepted: boolean }> {
110-
try {
111-
await this.http.post("/api/templates", req, options);
112-
// If we get here without error, the request was accepted (202) or succeeded
113-
return { accepted: true };
114-
} catch (error) {
115-
if (error instanceof ComputeClientError && error.status === 202) {
116-
return { accepted: true };
117-
}
118-
throw error;
119-
}
109+
): Promise<void> {
110+
await this.http.post("/api/templates", req, options);
120111
}
121112
}
122113

@@ -127,7 +118,11 @@ class InstancesNamespace {
127118
req: InstanceCreateRequest,
128119
options?: RequestOptions
129120
): Promise<InstanceCreateResponse> {
130-
return this.http.post<InstanceCreateResponse>("/api/instances", req, options);
121+
const result = await this.http.post<InstanceCreateResponse>("/api/instances", req, options);
122+
if (!result) {
123+
throw new Error("Compute gateway returned no instance body");
124+
}
125+
return result;
131126
}
132127

133128
async delete(runnerId: string, options?: RequestOptions): Promise<void> {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Strip the digest suffix from a container image reference.
3+
* Tags are immutable, so we resolve by tag rather than pinning to a digest.
4+
*
5+
* "ghcr.io/org/image:tag@sha256:abc..." -> "ghcr.io/org/image:tag"
6+
* "ghcr.io/org/image@sha256:abc..." -> "ghcr.io/org/image"
7+
* "ghcr.io/org/image:tag" -> "ghcr.io/org/image:tag" (unchanged)
8+
*/
9+
export function stripImageDigest(imageRef: string): string {
10+
return imageRef.split("@")[0] ?? imageRef;
11+
}

internal-packages/compute/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export { ComputeClient, ComputeClientError } from "./client.js";
22
export type { ComputeClientOptions } from "./client.js";
3+
export { stripImageDigest } from "./imageRef.js";
34
export {
45
TemplateCreateRequestSchema,
56
TemplateCallbackPayloadSchema,

0 commit comments

Comments
 (0)