@@ -9,6 +9,7 @@ import { resolveCredentialById, createClientFromCredentialId } from './credentia
99
1010// Docker client
1111let docker : Docker | null = null ;
12+ export type DockerArch = 'amd64' | 'arm64' ;
1213
1314// Runner image name
1415const RUNNER_IMAGE = process . env . RUNNER_IMAGE || 'myoung34/github-runner:latest' ;
@@ -63,13 +64,28 @@ export async function getDockerInfo(): Promise<object | null> {
6364 }
6465}
6566
67+ export function normalizeImageArchitecture ( architecture : string ) : string {
68+ if ( architecture === 'aarch64' ) return 'arm64' ;
69+ if ( architecture === 'x86_64' ) return 'amd64' ;
70+ return architecture ;
71+ }
72+
73+ export function assertImageArchitecture ( imageRef : string , actualArchitecture : string , expectedArchitecture : DockerArch ) : void {
74+ const normalized = normalizeImageArchitecture ( actualArchitecture ) ;
75+ if ( normalized !== expectedArchitecture ) {
76+ throw new Error (
77+ `Image ${ imageRef } architecture mismatch: expected ${ expectedArchitecture } , got ${ actualArchitecture } `
78+ ) ;
79+ }
80+ }
81+
6682/**
6783 * Pull the runner image for the specified platform
6884 * Note: Docker multi-arch images require explicit platform handling.
6985 * We pull with --platform and verify the architecture before use.
7086 */
7187export async function pullRunnerImage (
72- architecture : 'amd64' | 'arm64' = 'amd64'
88+ architecture : DockerArch = 'amd64'
7389) : Promise < string > {
7490 const d = initDocker ( ) ;
7591 const platform = `linux/${ architecture } ` ;
@@ -90,14 +106,13 @@ export async function pullRunnerImage(
90106 // Check if we already have the platform-specific tag with correct architecture
91107 try {
92108 const existingImage = await d . getImage ( platformTag ) . inspect ( ) ;
93- const imageArch = existingImage . Architecture ;
94- const normalizedImageArch = imageArch === 'aarch64' ? 'arm64' : imageArch ;
109+ const imageArch = normalizeImageArchitecture ( existingImage . Architecture ) ;
95110
96- if ( normalizedImageArch === architecture ) {
97- console . log ( `Image ${ platformTag } already exists with correct architecture (${ imageArch } )` ) ;
111+ if ( imageArch === architecture ) {
112+ console . log ( `Image ${ platformTag } already exists with correct architecture (${ existingImage . Architecture } )` ) ;
98113 return platformTag ;
99114 }
100- console . log ( `Image ${ platformTag } exists but has wrong architecture (${ imageArch } ), re-pulling...` ) ;
115+ console . log ( `Image ${ platformTag } exists but has wrong architecture (${ existingImage . Architecture } ), re-pulling...` ) ;
101116 } catch {
102117 // Image doesn't exist, need to pull
103118 }
@@ -129,6 +144,7 @@ export async function pullRunnerImage(
129144 // Verify the pulled image has the correct architecture
130145 const pulledImage = await d . getImage ( RUNNER_IMAGE ) . inspect ( ) ;
131146 console . log ( `Pulled image architecture: ${ pulledImage . Architecture } ` ) ;
147+ assertImageArchitecture ( RUNNER_IMAGE , pulledImage . Architecture , architecture ) ;
132148
133149 // Tag the pulled image with architecture-specific tag
134150 console . log ( `Tagging image as ${ platformTag } ...` ) ;
@@ -138,6 +154,7 @@ export async function pullRunnerImage(
138154 // Verify the tagged image
139155 const taggedImage = await d . getImage ( platformTag ) . inspect ( ) ;
140156 console . log ( `Tagged image ${ platformTag } architecture: ${ taggedImage . Architecture } ` ) ;
157+ assertImageArchitecture ( platformTag , taggedImage . Architecture , architecture ) ;
141158
142159 return platformTag ;
143160}
@@ -171,6 +188,7 @@ export async function createDockerRunner(
171188 if ( dockerArch !== 'amd64' && dockerArch !== 'arm64' ) {
172189 throw new Error ( `Unsupported Docker architecture: ${ architecture } ` ) ;
173190 }
191+ const platform = `linux/${ dockerArch } ` ;
174192
175193 // Resolve credential and get token
176194 const resolved = await resolveCredentialById ( credentialId ) ;
@@ -247,6 +265,7 @@ export async function createDockerRunner(
247265 // Create container using the architecture-specific image tag
248266 const container = await d . createContainer ( {
249267 Image : imageTag ,
268+ platform,
250269 name : `action-packer-${ runnerId } ` ,
251270 Env : env ,
252271 HostConfig : hostConfig ,
0 commit comments