Skip to content

Commit ecfa025

Browse files
committed
Run update-ca-certificates as root
1 parent d5e9c82 commit ecfa025

File tree

6 files changed

+158
-44
lines changed

6 files changed

+158
-44
lines changed

__tests__/helpers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ export const removeDanglingUpdaterContainers = async (): Promise<void> => {
2121
}
2222
}
2323

24+
// Wait a bit for network endpoints to be properly disconnected
25+
await new Promise(resolve => setTimeout(resolve, 1000))
26+
2427
await docker.pruneNetworks()
2528
await docker.pruneContainers()
2629
}

__tests__/updater-builder-integration.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ integration('UpdaterBuilder', () => {
4141
await ImageService.pull(PROXY_IMAGE_NAME)
4242
await ImageService.pull(updaterImageName('bundler'))
4343

44-
fs.mkdirSync(workingDirectory)
44+
fs.mkdirSync(workingDirectory, {recursive: true})
4545
})
4646

4747
afterEach(async () => {

dist/main/index.js

Lines changed: 62 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/main/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/container-service.ts

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,31 +35,101 @@ export const ContainerService = {
3535

3636
async run(container: Container): Promise<boolean> {
3737
try {
38-
const stream = await container.attach({
39-
stream: true,
40-
stdout: true,
41-
stderr: true
42-
})
38+
// Start the container
39+
await container.start()
40+
core.info(`Started container ${container.id}`)
41+
42+
// Check if this is a dependabot container (has the expected structure)
43+
const containerInfo = await container.inspect()
44+
const isDependabotContainer = containerInfo.Config?.Env?.some(env =>
45+
env.startsWith('DEPENDABOT_JOB_ID=')
46+
)
47+
48+
if (isDependabotContainer) {
49+
// For dependabot containers, run CA certificates update as root first
50+
await this.execCommand(
51+
container,
52+
['/usr/sbin/update-ca-certificates'],
53+
'root'
54+
)
55+
56+
// Then run the dependabot commands as dependabot user
57+
const dependabotCommands = [
58+
'mkdir -p /home/dependabot/dependabot-updater/output',
59+
'$DEPENDABOT_HOME/dependabot-updater/bin/run fetch_files',
60+
'$DEPENDABOT_HOME/dependabot-updater/bin/run update_files'
61+
]
62+
63+
for (const cmd of dependabotCommands) {
64+
await this.execCommand(
65+
container,
66+
['/bin/sh', '-c', cmd],
67+
'dependabot'
68+
)
69+
}
70+
} else {
71+
// For test containers and other containers, just wait for completion
72+
const outcome = await container.wait()
73+
if (outcome.StatusCode !== 0) {
74+
throw new Error(`Container exited with code ${outcome.StatusCode}`)
75+
}
76+
}
77+
78+
return true
79+
} catch (error) {
80+
core.info(`Failure running container ${container.id}: ${error}`)
81+
throw new ContainerRuntimeError(
82+
'The updater encountered one or more errors.'
83+
)
84+
} finally {
85+
try {
86+
await container.remove({v: true, force: true})
87+
core.info(`Cleaned up container ${container.id}`)
88+
} catch (error) {
89+
core.info(`Failed to clean up container ${container.id}: ${error}`)
90+
}
91+
}
92+
},
93+
94+
async execCommand(
95+
container: Container,
96+
cmd: string[],
97+
user: string
98+
): Promise<void> {
99+
const exec = await container.exec({
100+
Cmd: cmd,
101+
User: user,
102+
AttachStdout: true,
103+
AttachStderr: true
104+
})
105+
106+
const stream = await exec.start({})
107+
108+
// Wait for the stream to end
109+
await new Promise<void>((resolve, reject) => {
43110
container.modem.demuxStream(
44111
stream,
45112
outStream('updater'),
46113
errStream('updater')
47114
)
48115

49-
await container.start()
50-
const outcome = await container.wait()
116+
stream.on('end', () => {
117+
resolve()
118+
})
51119

52-
if (outcome.StatusCode === 0) {
53-
return true
54-
} else {
55-
core.info(`Failure running container ${container.id}`)
56-
throw new ContainerRuntimeError(
57-
'The updater encountered one or more errors.'
58-
)
59-
}
60-
} finally {
61-
await container.remove({v: true})
62-
core.info(`Cleaned up container ${container.id}`)
120+
stream.on('error', error => {
121+
reject(error)
122+
})
123+
})
124+
125+
// Wait a bit for the exec to complete properly
126+
await new Promise(resolve => setTimeout(resolve, 100))
127+
128+
const inspection = await exec.inspect()
129+
if (inspection.ExitCode !== 0) {
130+
throw new Error(
131+
`Command failed with exit code ${inspection.ExitCode}: ${cmd.join(' ')}`
132+
)
63133
}
64134
}
65135
}

src/updater-builder.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,13 @@ export class UpdaterBuilder {
2626
) {}
2727

2828
async run(containerName: string): Promise<Container> {
29-
const cmd = `/usr/sbin/update-ca-certificates &&\
30-
mkdir -p ${JOB_OUTPUT_PATH} &&\
31-
$DEPENDABOT_HOME/dependabot-updater/bin/run fetch_files &&\
32-
$DEPENDABOT_HOME/dependabot-updater/bin/run update_files`
33-
3429
const proxyUrl = await this.proxy.url()
3530
const container = await this.docker.createContainer({
3631
Image: this.updaterImage,
3732
name: containerName,
3833
AttachStdout: true,
3934
AttachStderr: true,
35+
User: 'dependabot',
4036
Env: [
4137
`GITHUB_ACTIONS=${process.env.GITHUB_ACTIONS}`,
4238
`DEPENDABOT_JOB_ID=${this.jobParams.jobId}`,
@@ -56,7 +52,8 @@ export class UpdaterBuilder {
5652
process.env.DEPENDABOT_ENABLE_CONNECTIVITY_CHECK || '1'
5753
}`
5854
],
59-
Cmd: ['sh', '-c', cmd],
55+
Cmd: ['/bin/sh'],
56+
Tty: true,
6057
HostConfig: {
6158
Memory: UPDATER_MAX_MEMORY,
6259
NetworkMode: this.proxy.networkName

0 commit comments

Comments
 (0)