@paklo/runner 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{api-client-BoQ6jjRB.d.mts → api-client-DZQQArbU.d.mts} +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/local/azure/index.d.mts +2 -2
- package/dist/local/azure/index.mjs +34 -26
- package/dist/local/azure/index.mjs.map +1 -1
- package/dist/local/index.d.mts +2 -2
- package/dist/local/index.mjs +1 -1
- package/dist/{run-BsKh8vDS.mjs → run-DLJ0FJ4t.mjs} +62 -62
- package/dist/run-DLJ0FJ4t.mjs.map +1 -0
- package/dist/{server-6BlJr2bw.d.mts → server-B6aYEkTC.d.mts} +20 -22
- package/dist/{server-BxUu1gGo.mjs → server-BkN82tIp.mjs} +2 -2
- package/dist/server-BkN82tIp.mjs.map +1 -0
- package/package.json +7 -7
- package/dist/run-BsKh8vDS.mjs.map +0 -1
- package/dist/server-BxUu1gGo.mjs.map +0 -1
|
@@ -46,4 +46,4 @@ declare class ApiClient {
|
|
|
46
46
|
}
|
|
47
47
|
//#endregion
|
|
48
48
|
export { JobParameters as a, SecretMasker as i, CredentialFetchingError as n, getJobParameters as o, JobDetailsFetchingError as r, ApiClient as t };
|
|
49
|
-
//# sourceMappingURL=api-client-
|
|
49
|
+
//# sourceMappingURL=api-client-DZQQArbU.d.mts.map
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as JobParameters, i as SecretMasker, n as CredentialFetchingError, o as getJobParameters, r as JobDetailsFetchingError, t as ApiClient } from "./api-client-
|
|
1
|
+
import { a as JobParameters, i as SecretMasker, n as CredentialFetchingError, o as getJobParameters, r as JobDetailsFetchingError, t as ApiClient } from "./api-client-DZQQArbU.mjs";
|
|
2
2
|
import Docker, { Container, Network } from "dockerode";
|
|
3
3
|
import { CertificateAuthority, DependabotCredential, DependabotJobConfig, DependabotProxyConfig, FileFetcherInput, FileUpdaterInput } from "@paklo/core/dependabot";
|
|
4
4
|
import { UsageTelemetryRequestData } from "@paklo/core/usage";
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as hasDigest, D as ApiClient, E as updaterImages, O as CredentialFetchingError, S as digestName, T as updaterImageName, _ as getOrgFromImage, a as Updater, b as extractUpdaterSha, c as JOB_INPUT_FILENAME, d as UpdaterBuilder, f as CONFIG_FILE_NAME, g as ImageService, h as getJobParameters, i as runJob, k as JobDetailsFetchingError, l as JOB_INPUT_PATH, m as JobParameters, n as JobRunnerUpdaterError, o as CA_CERT_FILENAME, p as ProxyBuilder, r as isRunningInDocker, s as CA_CERT_INPUT_PATH, t as JobRunnerImagingError, u as REPO_CONTENTS_PATH, v as ContainerRuntimeError, w as repositoryName, x as PROXY_IMAGE_NAME, y as ContainerService } from "./run-
|
|
1
|
+
import { C as hasDigest, D as ApiClient, E as updaterImages, O as CredentialFetchingError, S as digestName, T as updaterImageName, _ as getOrgFromImage, a as Updater, b as extractUpdaterSha, c as JOB_INPUT_FILENAME, d as UpdaterBuilder, f as CONFIG_FILE_NAME, g as ImageService, h as getJobParameters, i as runJob, k as JobDetailsFetchingError, l as JOB_INPUT_PATH, m as JobParameters, n as JobRunnerUpdaterError, o as CA_CERT_FILENAME, p as ProxyBuilder, r as isRunningInDocker, s as CA_CERT_INPUT_PATH, t as JobRunnerImagingError, u as REPO_CONTENTS_PATH, v as ContainerRuntimeError, w as repositoryName, x as PROXY_IMAGE_NAME, y as ContainerService } from "./run-DLJ0FJ4t.mjs";
|
|
2
2
|
import { logger } from "@paklo/core/logger";
|
|
3
3
|
import Docker from "dockerode";
|
|
4
4
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "../../api-client-
|
|
2
|
-
import { a as LocalJobsRunner, i as LocalDependabotServerOptions, n as LocalDependabotServer, o as LocalJobsRunnerOptions, s as RunJobsResult } from "../../server-
|
|
1
|
+
import "../../api-client-DZQQArbU.mjs";
|
|
2
|
+
import { a as LocalJobsRunner, i as LocalDependabotServerOptions, n as LocalDependabotServer, o as LocalJobsRunnerOptions, s as RunJobsResult } from "../../server-B6aYEkTC.mjs";
|
|
3
3
|
import { DependabotRequest } from "@paklo/core/dependabot";
|
|
4
4
|
import { AzdoPrExtractedWithProperties, AzdoPullRequestMergeStrategy, AzureDevOpsClientWrapper, AzureDevOpsRepositoryUrl } from "@paklo/core/azure";
|
|
5
5
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i as runJob } from "../../run-
|
|
2
|
-
import { n as LocalJobsRunner, t as LocalDependabotServer } from "../../server-
|
|
1
|
+
import { i as runJob } from "../../run-DLJ0FJ4t.mjs";
|
|
2
|
+
import { n as LocalJobsRunner, t as LocalDependabotServer } from "../../server-BkN82tIp.mjs";
|
|
3
3
|
import { logger } from "@paklo/core/logger";
|
|
4
4
|
import { readFile } from "node:fs/promises";
|
|
5
5
|
import { existsSync } from "node:fs";
|
|
6
|
-
import { DependabotJobBuilder, getBranchNameForUpdate,
|
|
6
|
+
import { DependabotJobBuilder, getBranchNameForUpdate, getPersistedPr, getPullRequestCloseReason, getPullRequestDescription, mapPackageEcosystemToPackageManager, normalizeBranchName, shouldSupersede } from "@paklo/core/dependabot";
|
|
7
7
|
import { AzureDevOpsClientWrapper, PR_DESCRIPTION_MAX_LENGTH, PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME, buildPullRequestProperties, getPullRequestChangedFiles, getPullRequestForDependencyNames, parsePullRequestProperties } from "@paklo/core/azure";
|
|
8
8
|
import { GitHubSecurityAdvisoryClient, SecurityVulnerabilitySchema, filterVulnerabilities, getGhsaPackageEcosystemFromDependabotPackageManager } from "@paklo/core/github";
|
|
9
9
|
|
|
@@ -37,14 +37,14 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
37
37
|
}
|
|
38
38
|
const openPullRequestsLimit = update["open-pull-requests-limit"];
|
|
39
39
|
const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);
|
|
40
|
-
const existingPullRequestsCount =
|
|
40
|
+
const existingPullRequestsCount = existingPullRequestsForPackageManager.length;
|
|
41
41
|
const openPullRequestsCount = affectedPullRequestIds.get(id).created.length + existingPullRequestsCount;
|
|
42
42
|
if (openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit) {
|
|
43
43
|
logger.warn(`Skipping pull request creation of '${title}' as the open pull requests limit (${openPullRequestsLimit}) has been reached`);
|
|
44
44
|
return true;
|
|
45
45
|
}
|
|
46
|
+
const persisted = getPersistedPr(data);
|
|
46
47
|
const changedFiles = getPullRequestChangedFiles(data);
|
|
47
|
-
const dependencies = getPullRequestDependencies(data);
|
|
48
48
|
const targetBranch = update["target-branch"] || await authorClient.getDefaultBranch({
|
|
49
49
|
project,
|
|
50
50
|
repository
|
|
@@ -53,8 +53,8 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
53
53
|
packageEcosystem: update["package-ecosystem"],
|
|
54
54
|
targetBranchName: targetBranch,
|
|
55
55
|
directory: update.directory || update.directories?.find((dir) => changedFiles[0]?.path?.startsWith(dir)),
|
|
56
|
-
dependencyGroupName:
|
|
57
|
-
dependencies:
|
|
56
|
+
dependencyGroupName: persisted["dependency-group-name"],
|
|
57
|
+
dependencies: persisted.dependencies,
|
|
58
58
|
separator: update["pull-request-branch-name"]?.separator
|
|
59
59
|
});
|
|
60
60
|
if ((existingBranchNames?.find((branch) => sourceBranch === branch) || []).length) {
|
|
@@ -91,7 +91,7 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
91
91
|
labels: update.labels?.map((label) => label?.trim()) || [],
|
|
92
92
|
workItems: update.milestone ? [update.milestone] : [],
|
|
93
93
|
changes: changedFiles,
|
|
94
|
-
properties: buildPullRequestProperties(packageManager,
|
|
94
|
+
properties: buildPullRequestProperties(packageManager, persisted)
|
|
95
95
|
});
|
|
96
96
|
if (autoApprove && approverClient && newPullRequestId) await approverClient.approvePullRequest({
|
|
97
97
|
project,
|
|
@@ -99,7 +99,20 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
99
99
|
pullRequestId: newPullRequestId
|
|
100
100
|
});
|
|
101
101
|
if (newPullRequestId) {
|
|
102
|
-
affectedPullRequestIds.get(id).created.push(
|
|
102
|
+
affectedPullRequestIds.get(id).created.push({
|
|
103
|
+
"pr-number": newPullRequestId,
|
|
104
|
+
...persisted
|
|
105
|
+
});
|
|
106
|
+
for (const existingPr of existingPullRequestsForPackageManager) if (shouldSupersede(persisted, existingPr)) {
|
|
107
|
+
logger.info(`Detected that existing PR #${existingPr["pr-number"]} is superseded by new PR #${newPullRequestId}`);
|
|
108
|
+
authorClient.abandonPullRequest({
|
|
109
|
+
project,
|
|
110
|
+
repository,
|
|
111
|
+
pullRequestId: existingPr["pr-number"],
|
|
112
|
+
comment: `Superseded by #${newPullRequestId}`,
|
|
113
|
+
deleteSourceBranch: true
|
|
114
|
+
});
|
|
115
|
+
}
|
|
103
116
|
return true;
|
|
104
117
|
}
|
|
105
118
|
return false;
|
|
@@ -109,7 +122,7 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
109
122
|
logger.warn(`Skipping pull request update as 'dryRun' is set to 'true'`);
|
|
110
123
|
return true;
|
|
111
124
|
}
|
|
112
|
-
const pullRequestToUpdate = getPullRequestForDependencyNames(existingPullRequests, packageManager, data["dependency-names"]);
|
|
125
|
+
const pullRequestToUpdate = getPullRequestForDependencyNames(existingPullRequests, packageManager, data["dependency-names"], data["dependency-group"]?.name);
|
|
113
126
|
if (!pullRequestToUpdate) {
|
|
114
127
|
logger.error(`Could not find pull request to update for package manager '${packageManager}' with dependencies '${data["dependency-names"].join(", ")}'`);
|
|
115
128
|
return false;
|
|
@@ -160,7 +173,7 @@ var AzureLocalDependabotServer = class extends LocalDependabotServer {
|
|
|
160
173
|
logger.warn(`Skipping warning as 'dryRun' is set to 'true'`);
|
|
161
174
|
return true;
|
|
162
175
|
}
|
|
163
|
-
const ids = affectedPullRequestIds.get(id).created.concat(affectedPullRequestIds.get(id).updated);
|
|
176
|
+
const ids = affectedPullRequestIds.get(id).created.map((pr) => pr["pr-number"]).concat(affectedPullRequestIds.get(id).updated);
|
|
164
177
|
for (const pullRequestId of ids) await authorClient.addCommentThread({
|
|
165
178
|
project,
|
|
166
179
|
repository,
|
|
@@ -241,7 +254,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
241
254
|
else updates = config.updates;
|
|
242
255
|
try {
|
|
243
256
|
await this.abandonPullRequestsWhereSourceRefIsDeleted(existingBranchNames, existingPullRequests);
|
|
244
|
-
return await this.performUpdates(server, updates, existingPullRequests, dependabotApiUrl, dependabotApiDockerUrl
|
|
257
|
+
return await this.performUpdates(server, updates, command, existingPullRequests, dependabotApiUrl, dependabotApiDockerUrl);
|
|
245
258
|
} finally {
|
|
246
259
|
server.stop();
|
|
247
260
|
}
|
|
@@ -254,8 +267,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
254
267
|
async abandonPullRequestsWhereSourceRefIsDeleted(existingBranchNames, existingPullRequests) {
|
|
255
268
|
if (!existingBranchNames || !existingPullRequests) return;
|
|
256
269
|
const { options: { url, dryRun }, authorClient } = this;
|
|
257
|
-
for (const
|
|
258
|
-
const pullRequest = existingPullRequests[pullRequestIndex];
|
|
270
|
+
for (const pullRequest of existingPullRequests) {
|
|
259
271
|
const pullRequestSourceRefName = normalizeBranchName(pullRequest.properties?.find((x) => x.name === PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME)?.value);
|
|
260
272
|
if (pullRequestSourceRefName && !existingBranchNames.includes(pullRequestSourceRefName)) {
|
|
261
273
|
if (!dryRun) {
|
|
@@ -277,7 +289,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
277
289
|
* @param updates The updates to perform.
|
|
278
290
|
* @param existingPullRequests The existing pull requests.
|
|
279
291
|
*/
|
|
280
|
-
async performUpdates(server, updates, existingPullRequests, dependabotApiUrl, dependabotApiDockerUrl
|
|
292
|
+
async performUpdates(server, updates, command, existingPullRequests, dependabotApiUrl, dependabotApiDockerUrl) {
|
|
281
293
|
const { options: { url, gitToken, githubToken, experiments, config, dryRun, securityAdvisoriesFile, secretMasker } } = this;
|
|
282
294
|
const results = [];
|
|
283
295
|
function makeRandomJobId() {
|
|
@@ -300,7 +312,6 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
300
312
|
let { updaterImage } = this.options;
|
|
301
313
|
updaterImage = updaterImage?.replace(/\{ecosystem\}/i, packageEcosystem);
|
|
302
314
|
const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);
|
|
303
|
-
const existingPullRequestDependenciesForPackageManager = Object.values(existingPullRequestsForPackageManager);
|
|
304
315
|
const builder = new DependabotJobBuilder({
|
|
305
316
|
source: {
|
|
306
317
|
provider: "azure",
|
|
@@ -324,10 +335,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
324
335
|
const securityUpdatesOnly = openPullRequestsLimit === 0;
|
|
325
336
|
if (securityUpdatesOnly) {
|
|
326
337
|
const id = makeRandomJobId();
|
|
327
|
-
({job, credentials} = builder.forDependenciesList({
|
|
328
|
-
id,
|
|
329
|
-
command
|
|
330
|
-
}));
|
|
338
|
+
({job, credentials} = builder.forDependenciesList({ id }));
|
|
331
339
|
({jobToken, credentialsToken} = this.makeTokens());
|
|
332
340
|
server.add({
|
|
333
341
|
id,
|
|
@@ -378,7 +386,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
378
386
|
}
|
|
379
387
|
server.clear(id);
|
|
380
388
|
}
|
|
381
|
-
const openPullRequestsCount =
|
|
389
|
+
const openPullRequestsCount = existingPullRequestsForPackageManager.length;
|
|
382
390
|
if (!(openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit)) {
|
|
383
391
|
const dependenciesHaveVulnerabilities = dependencyNamesToUpdate.length && securityVulnerabilities.length;
|
|
384
392
|
if (!securityUpdatesOnly || dependenciesHaveVulnerabilities) {
|
|
@@ -387,7 +395,7 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
387
395
|
id,
|
|
388
396
|
command,
|
|
389
397
|
dependencyNamesToUpdate,
|
|
390
|
-
existingPullRequests:
|
|
398
|
+
existingPullRequests: existingPullRequestsForPackageManager,
|
|
391
399
|
securityVulnerabilities
|
|
392
400
|
}));
|
|
393
401
|
({jobToken, credentialsToken} = this.makeTokens());
|
|
@@ -420,14 +428,14 @@ var AzureLocalJobsRunner = class extends LocalJobsRunner {
|
|
|
420
428
|
});
|
|
421
429
|
} else logger.info("Nothing to update; dependencies are not affected by any known vulnerability");
|
|
422
430
|
} else logger.warn(`Skipping update for ${packageEcosystem} packages as the open pull requests limit (${openPullRequestsLimit}) has already been reached`);
|
|
423
|
-
const numberOfPullRequestsToUpdate =
|
|
424
|
-
if (numberOfPullRequestsToUpdate > 0) if (!dryRun) for (const
|
|
431
|
+
const numberOfPullRequestsToUpdate = existingPullRequestsForPackageManager.length;
|
|
432
|
+
if (numberOfPullRequestsToUpdate > 0) if (!dryRun) for (const pullRequestToUpdate of existingPullRequestsForPackageManager) {
|
|
425
433
|
const id = makeRandomJobId();
|
|
426
434
|
({job, credentials} = builder.forUpdate({
|
|
427
435
|
id,
|
|
428
436
|
command,
|
|
429
|
-
existingPullRequests:
|
|
430
|
-
pullRequestToUpdate
|
|
437
|
+
existingPullRequests: existingPullRequestsForPackageManager,
|
|
438
|
+
pullRequestToUpdate,
|
|
431
439
|
securityVulnerabilities
|
|
432
440
|
}));
|
|
433
441
|
({jobToken, credentialsToken} = this.makeTokens());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/local/azure/server.ts","../../../src/local/azure/runner.ts"],"sourcesContent":["import type {\n AzdoPrExtractedWithProperties,\n AzureDevOpsClientWrapper,\n AzureDevOpsRepositoryUrl,\n} from '@paklo/core/azure';\nimport {\n type AzdoPullRequestMergeStrategy,\n buildPullRequestProperties,\n getPullRequestChangedFiles,\n getPullRequestForDependencyNames,\n PR_DESCRIPTION_MAX_LENGTH,\n parsePullRequestProperties,\n} from '@paklo/core/azure';\nimport {\n type DependabotRequest,\n getBranchNameForUpdate,\n getPullRequestCloseReason,\n getPullRequestDependencies,\n getPullRequestDescription,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport { LocalDependabotServer, type LocalDependabotServerOptions } from '../server';\n\nexport type AzureLocalDependabotServerOptions = LocalDependabotServerOptions & {\n url: AzureDevOpsRepositoryUrl;\n authorClient: AzureDevOpsClientWrapper;\n autoApprove: boolean;\n approverClient?: AzureDevOpsClientWrapper;\n setAutoComplete: boolean;\n mergeStrategy?: AzdoPullRequestMergeStrategy;\n autoCompleteIgnoreConfigIds: number[];\n existingBranchNames: string[] | undefined;\n existingPullRequests: AzdoPrExtractedWithProperties[];\n};\n\nexport class AzureLocalDependabotServer extends LocalDependabotServer {\n // biome-ignore lint/correctness/noUnusedPrivateClassMembers: options is used\n private readonly options: AzureLocalDependabotServerOptions;\n\n constructor(options: AzureLocalDependabotServerOptions) {\n super(options);\n this.options = options;\n }\n\n protected override async handle(id: string, request: DependabotRequest): Promise<boolean> {\n await super.handle(id, request); // common logic\n\n const { options, affectedPullRequestIds } = this;\n const {\n url,\n authorClient,\n approverClient,\n existingBranchNames,\n existingPullRequests,\n autoApprove,\n mergeStrategy,\n setAutoComplete,\n autoCompleteIgnoreConfigIds,\n author,\n dryRun,\n } = options;\n\n const { type, data } = request;\n const job = await this.job(id);\n if (!job) {\n logger.error(`No job found for ID '${id}', cannot process request of type '${type}'`);\n return false;\n }\n const { 'package-manager': packageManager } = job;\n logger.info(`Processing '${type}' for job ID '${id}'`);\n\n const update = this.update(id)!; // exists because job exists\n const { project, repository } = url;\n\n switch (type) {\n // Documentation on the 'data' model for each output type can be found here:\n // See: https://github.com/dependabot/cli/blob/main/internal/model/update.go\n\n case 'create_pull_request': {\n const title = data['pr-title'];\n if (dryRun) {\n logger.warn(`Skipping pull request creation of '${title}' as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Skip if active pull request limit reached.\n const openPullRequestsLimit = update['open-pull-requests-limit']!;\n\n // Parse the Dependabot metadata for the existing pull requests that are related to this update\n // Dependabot will use this to determine if we need to create new pull requests or update/close existing ones\n const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);\n const existingPullRequestsCount = Object.entries(existingPullRequestsForPackageManager).length;\n const openPullRequestsCount = affectedPullRequestIds.get(id)!.created.length + existingPullRequestsCount;\n const hasReachedOpenPullRequestLimit =\n openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit;\n\n if (hasReachedOpenPullRequestLimit) {\n logger.warn(\n `Skipping pull request creation of '${title}' as the open pull requests limit (${openPullRequestsLimit}) has been reached`,\n );\n return true;\n }\n\n const changedFiles = getPullRequestChangedFiles(data);\n const dependencies = getPullRequestDependencies(data);\n const targetBranch = update['target-branch'] || (await authorClient.getDefaultBranch({ project, repository }));\n const sourceBranch = getBranchNameForUpdate({\n packageEcosystem: update['package-ecosystem'],\n targetBranchName: targetBranch,\n directory: update.directory || update.directories?.find((dir) => changedFiles[0]?.path?.startsWith(dir)),\n dependencyGroupName: !Array.isArray(dependencies) ? dependencies['dependency-group-name'] : undefined,\n dependencies: !Array.isArray(dependencies) ? dependencies.dependencies : dependencies,\n separator: update['pull-request-branch-name']?.separator,\n });\n\n // Check if the source branch already exists or conflicts with an existing branch\n const existingBranch = existingBranchNames?.find((branch) => sourceBranch === branch) || [];\n if (existingBranch.length) {\n logger.error(\n `Unable to create pull request '${title}' as source branch '${sourceBranch}' already exists; Delete the existing branch and try again.`,\n );\n return false;\n }\n const conflictingBranches = existingBranchNames?.filter((branch) => sourceBranch.startsWith(branch)) || [];\n if (conflictingBranches.length) {\n logger.error(\n `Unable to create pull request '${title}' as source branch '${sourceBranch}' would conflict with existing branch(es) '${conflictingBranches.join(', ')}'; Delete the conflicting branch(es) and try again.`,\n );\n return false;\n }\n\n // Create a new pull request\n const newPullRequestId = await authorClient.createPullRequest({\n project: project,\n repository: repository,\n source: {\n commit: data['base-commit-sha'] || job.source.commit!,\n branch: sourceBranch,\n },\n target: {\n branch: targetBranch!,\n },\n author,\n title,\n description: getPullRequestDescription({\n packageManager,\n body: data['pr-body'],\n dependencies: data.dependencies,\n maxDescriptionLength: PR_DESCRIPTION_MAX_LENGTH,\n }),\n commitMessage: data['commit-message'],\n autoComplete: setAutoComplete\n ? {\n ignorePolicyConfigIds: autoCompleteIgnoreConfigIds,\n mergeStrategy: mergeStrategy ?? 'squash',\n }\n : undefined,\n assignees: update.assignees,\n labels: update.labels?.map((label) => label?.trim()) || [],\n workItems: update.milestone ? [update.milestone] : [],\n changes: changedFiles,\n properties: buildPullRequestProperties(packageManager, dependencies),\n });\n\n // Auto-approve the pull request, if required\n if (autoApprove && approverClient && newPullRequestId) {\n await approverClient.approvePullRequest({\n project: project,\n repository: repository,\n pullRequestId: newPullRequestId,\n });\n }\n\n // Store the new pull request ID, so we can keep track of the total number of open pull requests\n if (newPullRequestId) {\n affectedPullRequestIds.get(id)!.created.push(newPullRequestId);\n return true;\n }\n return false;\n }\n\n case 'update_pull_request': {\n if (dryRun) {\n logger.warn(`Skipping pull request update as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Find the pull request to update\n const pullRequestToUpdate = getPullRequestForDependencyNames(\n existingPullRequests,\n packageManager,\n data['dependency-names'],\n );\n if (!pullRequestToUpdate) {\n logger.error(\n `Could not find pull request to update for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,\n );\n return false;\n }\n\n // Update the pull request\n const pullRequestWasUpdated = await authorClient.updatePullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToUpdate.pullRequestId,\n commit: data['base-commit-sha'] || job.source.commit!,\n author,\n changes: getPullRequestChangedFiles(data),\n });\n\n // Re-approve the pull request, if required\n if (autoApprove && approverClient && pullRequestWasUpdated) {\n await approverClient.approvePullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToUpdate.pullRequestId,\n });\n }\n\n if (pullRequestWasUpdated) {\n affectedPullRequestIds.get(id)!.updated.push(pullRequestToUpdate.pullRequestId);\n return true;\n }\n return false;\n }\n\n case 'close_pull_request': {\n if (dryRun) {\n logger.warn(`Skipping pull request closure as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Find the pull request to close\n const pullRequestToClose = getPullRequestForDependencyNames(\n existingPullRequests,\n packageManager,\n data['dependency-names'],\n );\n if (!pullRequestToClose) {\n logger.error(\n `Could not find pull request to close for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,\n );\n return false;\n }\n\n // TODO: GitHub Dependabot will close with reason \"Superseded by ${new_pull_request_id}\" when another PR supersedes it.\n // How do we detect this? Do we need to?\n\n // Close the pull request\n const success = await authorClient.abandonPullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToClose.pullRequestId,\n comment: getPullRequestCloseReason(data),\n deleteSourceBranch: true,\n });\n if (success) {\n affectedPullRequestIds.get(id)!.closed.push(pullRequestToClose.pullRequestId);\n return true;\n }\n return false;\n }\n\n case 'record_update_job_warning': {\n if (dryRun) {\n logger.warn(`Skipping warning as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // add comment to each create/updated pull request\n const ids = affectedPullRequestIds.get(id)!.created.concat(affectedPullRequestIds.get(id)!.updated);\n for (const pullRequestId of ids) {\n await authorClient.addCommentThread({\n project: project,\n repository: repository,\n content: `### Dependabot Warning: ${data['warn-title']}\\n\\n${data['warn-description']}`,\n pullRequestId,\n });\n }\n\n return true;\n }\n\n // No action required\n case 'update_dependency_list':\n case 'create_dependency_submission':\n case 'mark_as_processed':\n case 'record_ecosystem_versions':\n case 'increment_metric':\n case 'record_ecosystem_meta':\n case 'record_cooldown_meta':\n case 'record_metrics': // from the runner\n return true;\n\n case 'record_update_job_error':\n case 'record_update_job_unknown_error': {\n const unknown = type === 'record_update_job_unknown_error';\n logger.error(\n `Update${unknown ? ' unknown ' : ''})job error: ${data['error-type']} ${JSON.stringify(data['error-details'])}`,\n );\n return true;\n }\n\n default:\n logger.warn(`Unknown dependabot request type '${type}', ignoring...`);\n return true;\n }\n }\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport {\n type AzdoPrExtractedWithProperties,\n AzureDevOpsClientWrapper,\n PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME,\n parsePullRequestProperties,\n} from '@paklo/core/azure';\nimport {\n type DependabotCredential,\n DependabotJobBuilder,\n type DependabotJobConfig,\n type DependabotUpdate,\n mapPackageEcosystemToPackageManager,\n normalizeBranchName,\n} from '@paklo/core/dependabot';\nimport {\n filterVulnerabilities,\n GitHubSecurityAdvisoryClient,\n getGhsaPackageEcosystemFromDependabotPackageManager,\n type Package,\n type SecurityVulnerability,\n SecurityVulnerabilitySchema,\n} from '@paklo/core/github';\nimport { logger } from '@paklo/core/logger';\nimport { type RunJobOptions, runJob } from '../../run';\nimport { LocalJobsRunner, type LocalJobsRunnerOptions, type RunJobsResult } from '../runner';\nimport { AzureLocalDependabotServer, type AzureLocalDependabotServerOptions } from './server';\n\nexport type AzureLocalJobsRunnerOptions = LocalJobsRunnerOptions &\n Omit<\n AzureLocalDependabotServerOptions,\n 'authorClient' | 'approverClient' | 'existingBranchNames' | 'existingPullRequests'\n > & {\n port?: number;\n securityAdvisoriesFile?: string;\n gitToken: string;\n githubToken?: string;\n autoApproveToken?: string;\n };\n\nexport class AzureLocalJobsRunner extends LocalJobsRunner {\n // biome-ignore-start lint/correctness/noUnusedPrivateClassMembers: variables are used\n private readonly options: AzureLocalJobsRunnerOptions;\n private readonly authorClient: AzureDevOpsClientWrapper;\n private readonly approverClient?: AzureDevOpsClientWrapper;\n // biome-ignore-end lint/correctness/noUnusedPrivateClassMembers: variables are used\n\n constructor(options: AzureLocalJobsRunnerOptions) {\n super({ ...options });\n this.options = options;\n const { url, gitToken, autoApprove, debug } = this.options;\n\n // Initialise the DevOps API clients (one for authoring the other for auto-approving (if configured))\n this.authorClient = new AzureDevOpsClientWrapper(url, gitToken, debug);\n this.approverClient = autoApprove\n ? new AzureDevOpsClientWrapper(url, options.autoApproveToken || gitToken, debug)\n : undefined;\n }\n\n public override async run(): Promise<RunJobsResult> {\n await super.run(); // common logic\n\n const {\n options: { url, port, config, targetUpdateIds, command },\n authorClient,\n approverClient,\n } = this;\n\n // Print a warning about multi-ecosystem updates not being fully supported\n // TODO: Implement full support for multi-ecosystem updates (not sure this will be possible on the local model)\n if (config['multi-ecosystem-groups'] || config.updates?.some((u) => u['multi-ecosystem-group'])) {\n logger.warn(\n 'Multi-ecosystem updates are not working yet. Only parsing and validation is supported at this time.',\n );\n }\n\n // Print a warning about the required workarounds for security-only updates, if any update is configured as such\n // TODO: If and when Dependabot supports a better way to do security-only updates, remove this.\n if (config.updates?.some((u) => u['open-pull-requests-limit'] === 0)) {\n logger.warn(\n 'Security-only updates incur a slight performance overhead due to limitations in Dependabot CLI. For more info, see: https://github.com/mburumaxwell/paklo/blob/main/README.md#configuring-security-advisories-and-known-vulnerabilities',\n );\n }\n\n // Fetch the active pull requests created by the author user\n const existingBranchNames = await authorClient.getBranchNames({ project: url.project, repository: url.repository });\n const existingPullRequests = await authorClient.getActivePullRequestProperties({\n project: url.project,\n repository: url.repository,\n creatorId: await authorClient.getUserId(),\n });\n\n // Prepare local server\n const serverOptions: AzureLocalDependabotServerOptions = {\n authorClient,\n approverClient,\n existingBranchNames,\n existingPullRequests,\n ...this.options,\n };\n const server = new AzureLocalDependabotServer(serverOptions);\n server.start(port);\n // give the server a second to start\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // The API urls is constant when working in this CLI. Asking people to setup NGROK or similar just to get\n // HTTPS for the job token to be used is too much hassle.\n // Using same value for dependabotApiUrl and dependabotApiDockerUrl so as to capture /record_metrics calls.\n const dependabotApiUrl = `http://host.docker.internal:${server.port}/api`;\n const dependabotApiDockerUrl = dependabotApiUrl;\n\n // If update identifiers are specified, select them; otherwise handle all\n let updates: DependabotUpdate[] = [];\n if (targetUpdateIds && targetUpdateIds.length > 0) {\n for (const id of targetUpdateIds) {\n const upd = config.updates[id];\n if (!upd) {\n logger.warn(\n `\n Unable to find target update id '${id}'.\n This value should be a zero based index of the update in your config file.\n Expected range: 0-${config.updates.length - 1}\n `,\n );\n } else {\n updates.push(upd);\n }\n }\n } else {\n updates = config.updates;\n }\n\n try {\n // Abandon all pull requests where the source branch has been deleted\n await this.abandonPullRequestsWhereSourceRefIsDeleted(existingBranchNames, existingPullRequests);\n\n // Perform updates for each of the [targeted] update blocks in dependabot.yaml\n return await this.performUpdates(\n server,\n updates,\n existingPullRequests,\n dependabotApiUrl,\n dependabotApiDockerUrl,\n command,\n );\n } finally {\n server.stop();\n }\n }\n\n /**\n * Abandon all pull requests where the source branch has been deleted.\n * @param existingBranchNames The names of the existing branches.\n * @param existingPullRequests The existing pull requests.\n */\n private async abandonPullRequestsWhereSourceRefIsDeleted(\n existingBranchNames?: string[],\n existingPullRequests?: AzdoPrExtractedWithProperties[],\n ): Promise<void> {\n if (!existingBranchNames || !existingPullRequests) return;\n\n const {\n options: { url, dryRun },\n authorClient,\n } = this;\n for (const pullRequestIndex in existingPullRequests) {\n const pullRequest = existingPullRequests[pullRequestIndex]!;\n const pullRequestSourceRefName = normalizeBranchName(\n pullRequest.properties?.find((x) => x.name === PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME)?.value,\n );\n if (pullRequestSourceRefName && !existingBranchNames.includes(pullRequestSourceRefName)) {\n // The source branch for the pull request has been deleted; abandon the pull request (if not dry run)\n if (!dryRun) {\n logger.warn(\n `Detected source branch for PR #${pullRequest.pullRequestId} has been deleted; The pull request will be abandoned`,\n );\n await authorClient.abandonPullRequest({\n project: url.project,\n repository: url.repository,\n pullRequestId: pullRequest.pullRequestId,\n // comment:\n // 'OK, I won't notify you again about this release, but will get in touch when a new version is available. ' +\n // 'If you'd rather skip all updates until the next major or minor version, add an ' +\n // '[`ignore` condition](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#ignore--) ' +\n // 'with the desired `update-types` to your config file.',\n comment:\n 'It might be a good idea to add an ' +\n '[`ignore` condition](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#ignore--) ' +\n 'with the desired `update-types` to your config file.',\n });\n }\n // Remove the pull request from the list of existing pull requests to ensures that we don't attempt to update it later in the process.\n existingPullRequests.splice(existingPullRequests.indexOf(pullRequest), 1);\n }\n }\n }\n\n /**\n * Performs the updates.\n * @param server The local Dependabot server.\n * @param updates The updates to perform.\n * @param existingPullRequests The existing pull requests.\n */\n private async performUpdates(\n server: AzureLocalDependabotServer,\n updates: DependabotUpdate[],\n existingPullRequests: AzdoPrExtractedWithProperties[],\n dependabotApiUrl: string,\n dependabotApiDockerUrl?: string,\n command?: DependabotJobConfig['command'],\n ): Promise<RunJobsResult> {\n const {\n options: { url, gitToken, githubToken, experiments, config, dryRun, securityAdvisoriesFile, secretMasker },\n } = this;\n\n const results: RunJobsResult = [];\n\n function makeRandomJobId(): string {\n const array = new Uint32Array(1);\n crypto.getRandomValues(array);\n return `${array[0]! % 10000000000}`; // Limit to 10 digits to match GitHub's job IDs\n }\n\n function makeUsageData(job: DependabotJobConfig): RunJobOptions['usage'] {\n return {\n trigger: 'user',\n provider: job.source.provider,\n owner: url.value.toString(),\n project: `${url.value.toString().replace(/\\/$/, '')}/${url.project}`,\n 'package-manager': job['package-manager'],\n };\n }\n\n for (const update of updates) {\n const packageEcosystem = update['package-ecosystem'];\n const packageManager = mapPackageEcosystemToPackageManager(packageEcosystem);\n\n // If there is an updater image, replace the placeholder in it\n let { updaterImage } = this.options;\n updaterImage = updaterImage?.replace(/\\{ecosystem\\}/i, packageEcosystem);\n\n // Parse the Dependabot metadata for the existing pull requests that are related to this update\n // Dependabot will use this to determine if we need to create new pull requests or update/close existing ones\n const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);\n const existingPullRequestDependenciesForPackageManager = Object.values(existingPullRequestsForPackageManager);\n\n const builder = new DependabotJobBuilder({\n source: { provider: 'azure', ...url },\n config,\n update,\n systemAccessToken: gitToken,\n githubToken,\n experiments,\n debug: false,\n });\n\n let job: DependabotJobConfig | undefined;\n let credentials: DependabotCredential[] | undefined;\n let jobToken: string;\n let credentialsToken: string;\n\n const debug = this.options.debug;\n\n // If this is a security-only update (i.e. 'open-pull-requests-limit: 0'), then we first need to discover the dependencies\n // that need updating and check each one for vulnerabilities. This is because Dependabot requires the list of vulnerable dependencies\n // to be supplied in the job definition of security-only update job, it will not automatically discover them like a versioned update does.\n // https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#overriding-the-default-behavior-with-a-configuration-file\n const securityVulnerabilities: SecurityVulnerability[] = [];\n const dependencyNamesToUpdate: string[] = [];\n const openPullRequestsLimit = update['open-pull-requests-limit']!;\n const securityUpdatesOnly = openPullRequestsLimit === 0;\n if (securityUpdatesOnly) {\n // Run an update job to discover all dependencies\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forDependenciesList({ id, command }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n\n const outputs = server.requests(id);\n const packagesToCheckForVulnerabilities: Package[] | undefined = outputs!\n .find((o) => o.type === 'update_dependency_list')\n ?.data.dependencies?.map((d) => ({ name: d.name, version: d.version }));\n if (packagesToCheckForVulnerabilities?.length) {\n logger.info(\n `Detected ${packagesToCheckForVulnerabilities.length} dependencies; Checking for vulnerabilities...`,\n );\n\n // parse security advisories from file (private)\n if (securityAdvisoriesFile) {\n const filePath = securityAdvisoriesFile;\n if (existsSync(filePath)) {\n const fileContents = await readFile(filePath, 'utf-8');\n securityVulnerabilities.push(\n ...(await SecurityVulnerabilitySchema.array().parseAsync(JSON.parse(fileContents))),\n );\n } else {\n logger.info(`Private security advisories file '${filePath}' does not exist`);\n }\n }\n if (githubToken) {\n const ghsaClient = new GitHubSecurityAdvisoryClient(githubToken);\n const githubVulnerabilities = await ghsaClient.getSecurityVulnerabilitiesAsync(\n getGhsaPackageEcosystemFromDependabotPackageManager(packageManager),\n packagesToCheckForVulnerabilities || [],\n );\n securityVulnerabilities.push(...githubVulnerabilities);\n } else {\n logger.info(\n 'GitHub access token is not provided; Checking for vulnerabilities from GitHub is skipped. ' +\n 'This is not an issue if you are using private security advisories file.',\n );\n }\n\n const filtered = filterVulnerabilities(securityVulnerabilities);\n securityVulnerabilities.splice(0); // clear array\n securityVulnerabilities.push(...filtered);\n\n // Only update dependencies that have vulnerabilities\n dependencyNamesToUpdate.push(...Array.from(new Set(securityVulnerabilities.map((v) => v.package.name))));\n logger.info(\n `Detected ${securityVulnerabilities.length} vulnerabilities affecting ${dependencyNamesToUpdate.length} dependencies`,\n );\n if (dependencyNamesToUpdate.length) {\n logger.trace(dependencyNamesToUpdate);\n }\n } else {\n logger.info(`No vulnerabilities detected for update ${update['package-ecosystem']} in ${update.directory}`);\n server.clear(id);\n continue; // nothing more to do for this update\n }\n\n server.clear(id);\n }\n\n // Run an update job for \"all dependencies\"; this will create new pull requests for dependencies that need updating\n const openPullRequestsCount = Object.entries(existingPullRequestsForPackageManager).length;\n const hasReachedOpenPullRequestLimit =\n openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit;\n if (!hasReachedOpenPullRequestLimit) {\n const dependenciesHaveVulnerabilities = dependencyNamesToUpdate.length && securityVulnerabilities.length;\n if (!securityUpdatesOnly || dependenciesHaveVulnerabilities) {\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forUpdate({\n id,\n command,\n dependencyNamesToUpdate,\n existingPullRequests: existingPullRequestDependenciesForPackageManager,\n securityVulnerabilities,\n }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n const { success, message } = await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n const affectedPrs = server.allAffectedPrs(id);\n server.clear(id);\n results.push({ id, success, message, affectedPrs });\n } else {\n logger.info('Nothing to update; dependencies are not affected by any known vulnerability');\n }\n } else {\n logger.warn(\n `Skipping update for ${packageEcosystem} packages as the open pull requests limit (${openPullRequestsLimit}) has already been reached`,\n );\n }\n\n // If there are existing pull requests, run an update job for each one; this will resolve merge conflicts and close pull requests that are no longer needed\n const numberOfPullRequestsToUpdate = Object.keys(existingPullRequestsForPackageManager).length;\n if (numberOfPullRequestsToUpdate > 0) {\n if (!dryRun) {\n for (const pullRequestId in existingPullRequestsForPackageManager) {\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forUpdate({\n id,\n command,\n existingPullRequests: existingPullRequestDependenciesForPackageManager,\n pullRequestToUpdate: existingPullRequestsForPackageManager[pullRequestId]!,\n securityVulnerabilities,\n }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n const { success, message } = await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n const affectedPrs = server.allAffectedPrs(id);\n server.clear(id);\n results.push({ id, success, message, affectedPrs });\n }\n } else {\n logger.warn(\n `Skipping update of ${numberOfPullRequestsToUpdate} existing ${packageEcosystem} package pull request(s) as 'dryRun' is set to 'true'`,\n );\n }\n }\n }\n\n return results;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/local/azure/server.ts","../../../src/local/azure/runner.ts"],"sourcesContent":["import type {\n AzdoPrExtractedWithProperties,\n AzureDevOpsClientWrapper,\n AzureDevOpsRepositoryUrl,\n} from '@paklo/core/azure';\nimport {\n type AzdoPullRequestMergeStrategy,\n buildPullRequestProperties,\n getPullRequestChangedFiles,\n getPullRequestForDependencyNames,\n PR_DESCRIPTION_MAX_LENGTH,\n parsePullRequestProperties,\n} from '@paklo/core/azure';\nimport {\n type DependabotRequest,\n getBranchNameForUpdate,\n getPersistedPr,\n getPullRequestCloseReason,\n getPullRequestDescription,\n shouldSupersede,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport { LocalDependabotServer, type LocalDependabotServerOptions } from '../server';\n\nexport type AzureLocalDependabotServerOptions = LocalDependabotServerOptions & {\n url: AzureDevOpsRepositoryUrl;\n authorClient: AzureDevOpsClientWrapper;\n autoApprove: boolean;\n approverClient?: AzureDevOpsClientWrapper;\n setAutoComplete: boolean;\n mergeStrategy?: AzdoPullRequestMergeStrategy;\n autoCompleteIgnoreConfigIds: number[];\n existingBranchNames: string[] | undefined;\n existingPullRequests: AzdoPrExtractedWithProperties[];\n};\n\nexport class AzureLocalDependabotServer extends LocalDependabotServer {\n // biome-ignore lint/correctness/noUnusedPrivateClassMembers: options is used\n private readonly options: AzureLocalDependabotServerOptions;\n\n constructor(options: AzureLocalDependabotServerOptions) {\n super(options);\n this.options = options;\n }\n\n protected override async handle(id: string, request: DependabotRequest): Promise<boolean> {\n await super.handle(id, request); // common logic\n\n const { options, affectedPullRequestIds } = this;\n const {\n url,\n authorClient,\n approverClient,\n existingBranchNames,\n existingPullRequests,\n autoApprove,\n mergeStrategy,\n setAutoComplete,\n autoCompleteIgnoreConfigIds,\n author,\n dryRun,\n } = options;\n\n const { type, data } = request;\n const job = await this.job(id);\n if (!job) {\n logger.error(`No job found for ID '${id}', cannot process request of type '${type}'`);\n return false;\n }\n const { 'package-manager': packageManager } = job;\n logger.info(`Processing '${type}' for job ID '${id}'`);\n\n const update = this.update(id)!; // exists because job exists\n const { project, repository } = url;\n\n switch (type) {\n // Documentation on the 'data' model for each output type can be found here:\n // See: https://github.com/dependabot/cli/blob/main/internal/model/update.go\n\n case 'create_pull_request': {\n const title = data['pr-title'];\n if (dryRun) {\n logger.warn(`Skipping pull request creation of '${title}' as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Skip if active pull request limit reached.\n const openPullRequestsLimit = update['open-pull-requests-limit']!;\n\n // Parse the Dependabot metadata for the existing pull requests that are related to this update\n // Dependabot will use this to determine if we need to create new pull requests or update/close existing ones\n const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);\n const existingPullRequestsCount = existingPullRequestsForPackageManager.length;\n const openPullRequestsCount = affectedPullRequestIds.get(id)!.created.length + existingPullRequestsCount;\n const hasReachedOpenPullRequestLimit =\n openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit;\n\n if (hasReachedOpenPullRequestLimit) {\n logger.warn(\n `Skipping pull request creation of '${title}' as the open pull requests limit (${openPullRequestsLimit}) has been reached`,\n );\n return true;\n }\n\n const persisted = getPersistedPr(data);\n const changedFiles = getPullRequestChangedFiles(data);\n const targetBranch = update['target-branch'] || (await authorClient.getDefaultBranch({ project, repository }));\n const sourceBranch = getBranchNameForUpdate({\n packageEcosystem: update['package-ecosystem'],\n targetBranchName: targetBranch,\n directory: update.directory || update.directories?.find((dir) => changedFiles[0]?.path?.startsWith(dir)),\n dependencyGroupName: persisted['dependency-group-name'],\n dependencies: persisted.dependencies,\n separator: update['pull-request-branch-name']?.separator,\n });\n\n // Check if the source branch already exists or conflicts with an existing branch\n const existingBranch = existingBranchNames?.find((branch) => sourceBranch === branch) || [];\n if (existingBranch.length) {\n logger.error(\n `Unable to create pull request '${title}' as source branch '${sourceBranch}' already exists; Delete the existing branch and try again.`,\n );\n return false;\n }\n const conflictingBranches = existingBranchNames?.filter((branch) => sourceBranch.startsWith(branch)) || [];\n if (conflictingBranches.length) {\n logger.error(\n `Unable to create pull request '${title}' as source branch '${sourceBranch}' would conflict with existing branch(es) '${conflictingBranches.join(', ')}'; Delete the conflicting branch(es) and try again.`,\n );\n return false;\n }\n\n // Create a new pull request\n const newPullRequestId = await authorClient.createPullRequest({\n project: project,\n repository: repository,\n source: {\n commit: data['base-commit-sha'] || job.source.commit!,\n branch: sourceBranch,\n },\n target: {\n branch: targetBranch!,\n },\n author,\n title,\n description: getPullRequestDescription({\n packageManager,\n body: data['pr-body'],\n dependencies: data.dependencies,\n maxDescriptionLength: PR_DESCRIPTION_MAX_LENGTH,\n }),\n commitMessage: data['commit-message'],\n autoComplete: setAutoComplete\n ? {\n ignorePolicyConfigIds: autoCompleteIgnoreConfigIds,\n mergeStrategy: mergeStrategy ?? 'squash',\n }\n : undefined,\n assignees: update.assignees,\n labels: update.labels?.map((label) => label?.trim()) || [],\n workItems: update.milestone ? [update.milestone] : [],\n changes: changedFiles,\n properties: buildPullRequestProperties(packageManager, persisted),\n });\n\n // Auto-approve the pull request, if required\n if (autoApprove && approverClient && newPullRequestId) {\n await approverClient.approvePullRequest({\n project: project,\n repository: repository,\n pullRequestId: newPullRequestId,\n });\n }\n\n // Store the new pull request ID, so we can keep track of the total number of open pull requests\n if (newPullRequestId) {\n affectedPullRequestIds.get(id)!.created.push({\n 'pr-number': newPullRequestId,\n ...persisted,\n });\n\n // Check if any existing pull requests are now superseded by this new pull request\n for (const existingPr of existingPullRequestsForPackageManager) {\n if (shouldSupersede(persisted, existingPr)) {\n logger.info(\n `Detected that existing PR #${existingPr['pr-number']} is superseded by new PR #${newPullRequestId}`,\n );\n\n // The updater leaves the PR open for the backend to close with a comment that it has been superseded\n authorClient.abandonPullRequest({\n project: project,\n repository: repository,\n pullRequestId: existingPr['pr-number'],\n comment: `Superseded by #${newPullRequestId}`,\n deleteSourceBranch: true,\n });\n }\n }\n\n return true;\n }\n return false;\n }\n\n case 'update_pull_request': {\n if (dryRun) {\n logger.warn(`Skipping pull request update as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Find the pull request to update\n const pullRequestToUpdate = getPullRequestForDependencyNames(\n existingPullRequests,\n packageManager,\n data['dependency-names'],\n data['dependency-group']?.name,\n );\n if (!pullRequestToUpdate) {\n logger.error(\n `Could not find pull request to update for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,\n );\n return false;\n }\n\n // Update the pull request\n const pullRequestWasUpdated = await authorClient.updatePullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToUpdate.pullRequestId,\n commit: data['base-commit-sha'] || job.source.commit!,\n author,\n changes: getPullRequestChangedFiles(data),\n });\n\n // Re-approve the pull request, if required\n if (autoApprove && approverClient && pullRequestWasUpdated) {\n await approverClient.approvePullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToUpdate.pullRequestId,\n });\n }\n\n if (pullRequestWasUpdated) {\n affectedPullRequestIds.get(id)!.updated.push(pullRequestToUpdate.pullRequestId);\n return true;\n }\n return false;\n }\n\n case 'close_pull_request': {\n if (dryRun) {\n logger.warn(`Skipping pull request closure as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // Find the pull request to close\n const pullRequestToClose = getPullRequestForDependencyNames(\n existingPullRequests,\n packageManager,\n data['dependency-names'],\n );\n if (!pullRequestToClose) {\n logger.error(\n `Could not find pull request to close for package manager '${packageManager}' with dependencies '${data['dependency-names'].join(', ')}'`,\n );\n return false;\n }\n\n // Close the pull request\n const success = await authorClient.abandonPullRequest({\n project: project,\n repository: repository,\n pullRequestId: pullRequestToClose.pullRequestId,\n comment: getPullRequestCloseReason(data),\n deleteSourceBranch: true,\n });\n if (success) {\n affectedPullRequestIds.get(id)!.closed.push(pullRequestToClose.pullRequestId);\n return true;\n }\n return false;\n }\n\n case 'record_update_job_warning': {\n if (dryRun) {\n logger.warn(`Skipping warning as 'dryRun' is set to 'true'`);\n return true;\n }\n\n // add comment to each create/updated pull request\n const ids = affectedPullRequestIds\n .get(id)!\n .created.map((pr) => pr['pr-number'])\n .concat(affectedPullRequestIds.get(id)!.updated);\n for (const pullRequestId of ids) {\n await authorClient.addCommentThread({\n project: project,\n repository: repository,\n content: `### Dependabot Warning: ${data['warn-title']}\\n\\n${data['warn-description']}`,\n pullRequestId,\n });\n }\n\n return true;\n }\n\n // No action required\n case 'update_dependency_list':\n case 'create_dependency_submission':\n case 'mark_as_processed':\n case 'record_ecosystem_versions':\n case 'increment_metric':\n case 'record_ecosystem_meta':\n case 'record_cooldown_meta':\n case 'record_metrics': // from the runner\n return true;\n\n case 'record_update_job_error':\n case 'record_update_job_unknown_error': {\n const unknown = type === 'record_update_job_unknown_error';\n logger.error(\n `Update${unknown ? ' unknown ' : ''})job error: ${data['error-type']} ${JSON.stringify(data['error-details'])}`,\n );\n return true;\n }\n\n default:\n logger.warn(`Unknown dependabot request type '${type}', ignoring...`);\n return true;\n }\n }\n}\n","import { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport {\n type AzdoPrExtractedWithProperties,\n AzureDevOpsClientWrapper,\n PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME,\n parsePullRequestProperties,\n} from '@paklo/core/azure';\nimport {\n type DependabotCommand,\n type DependabotCredential,\n DependabotJobBuilder,\n type DependabotJobConfig,\n type DependabotUpdate,\n mapPackageEcosystemToPackageManager,\n normalizeBranchName,\n} from '@paklo/core/dependabot';\nimport {\n filterVulnerabilities,\n GitHubSecurityAdvisoryClient,\n getGhsaPackageEcosystemFromDependabotPackageManager,\n type Package,\n type SecurityVulnerability,\n SecurityVulnerabilitySchema,\n} from '@paklo/core/github';\nimport { logger } from '@paklo/core/logger';\nimport { type RunJobOptions, runJob } from '../../run';\nimport { LocalJobsRunner, type LocalJobsRunnerOptions, type RunJobsResult } from '../runner';\nimport { AzureLocalDependabotServer, type AzureLocalDependabotServerOptions } from './server';\n\nexport type AzureLocalJobsRunnerOptions = LocalJobsRunnerOptions &\n Omit<\n AzureLocalDependabotServerOptions,\n 'authorClient' | 'approverClient' | 'existingBranchNames' | 'existingPullRequests'\n > & {\n port?: number;\n securityAdvisoriesFile?: string;\n gitToken: string;\n githubToken?: string;\n autoApproveToken?: string;\n };\n\nexport class AzureLocalJobsRunner extends LocalJobsRunner {\n // biome-ignore-start lint/correctness/noUnusedPrivateClassMembers: variables are used\n private readonly options: AzureLocalJobsRunnerOptions;\n private readonly authorClient: AzureDevOpsClientWrapper;\n private readonly approverClient?: AzureDevOpsClientWrapper;\n // biome-ignore-end lint/correctness/noUnusedPrivateClassMembers: variables are used\n\n constructor(options: AzureLocalJobsRunnerOptions) {\n super({ ...options });\n this.options = options;\n const { url, gitToken, autoApprove, debug } = this.options;\n\n // Initialise the DevOps API clients (one for authoring the other for auto-approving (if configured))\n this.authorClient = new AzureDevOpsClientWrapper(url, gitToken, debug);\n this.approverClient = autoApprove\n ? new AzureDevOpsClientWrapper(url, options.autoApproveToken || gitToken, debug)\n : undefined;\n }\n\n public override async run(): Promise<RunJobsResult> {\n await super.run(); // common logic\n\n const {\n options: { url, port, config, targetUpdateIds, command },\n authorClient,\n approverClient,\n } = this;\n\n // Print a warning about multi-ecosystem updates not being fully supported\n // TODO: Implement full support for multi-ecosystem updates (not sure this will be possible on the local model)\n if (config['multi-ecosystem-groups'] || config.updates?.some((u) => u['multi-ecosystem-group'])) {\n logger.warn(\n 'Multi-ecosystem updates are not working yet. Only parsing and validation is supported at this time.',\n );\n }\n\n // Print a warning about the required workarounds for security-only updates, if any update is configured as such\n // TODO: If and when Dependabot supports a better way to do security-only updates, remove this.\n if (config.updates?.some((u) => u['open-pull-requests-limit'] === 0)) {\n logger.warn(\n 'Security-only updates incur a slight performance overhead due to limitations in Dependabot CLI. For more info, see: https://github.com/mburumaxwell/paklo/blob/main/README.md#configuring-security-advisories-and-known-vulnerabilities',\n );\n }\n\n // Fetch the active pull requests created by the author user\n const existingBranchNames = await authorClient.getBranchNames({ project: url.project, repository: url.repository });\n const existingPullRequests = await authorClient.getActivePullRequestProperties({\n project: url.project,\n repository: url.repository,\n creatorId: await authorClient.getUserId(),\n });\n\n // Prepare local server\n const serverOptions: AzureLocalDependabotServerOptions = {\n authorClient,\n approverClient,\n existingBranchNames,\n existingPullRequests,\n ...this.options,\n };\n const server = new AzureLocalDependabotServer(serverOptions);\n server.start(port);\n // give the server a second to start\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n // The API urls is constant when working in this CLI. Asking people to setup NGROK or similar just to get\n // HTTPS for the job token to be used is too much hassle.\n // Using same value for dependabotApiUrl and dependabotApiDockerUrl so as to capture /record_metrics calls.\n const dependabotApiUrl = `http://host.docker.internal:${server.port}/api`;\n const dependabotApiDockerUrl = dependabotApiUrl;\n\n // If update identifiers are specified, select them; otherwise handle all\n let updates: DependabotUpdate[] = [];\n if (targetUpdateIds && targetUpdateIds.length > 0) {\n for (const id of targetUpdateIds) {\n const upd = config.updates[id];\n if (!upd) {\n logger.warn(\n `\n Unable to find target update id '${id}'.\n This value should be a zero based index of the update in your config file.\n Expected range: 0-${config.updates.length - 1}\n `,\n );\n } else {\n updates.push(upd);\n }\n }\n } else {\n updates = config.updates;\n }\n\n try {\n // Abandon all pull requests where the source branch has been deleted\n await this.abandonPullRequestsWhereSourceRefIsDeleted(existingBranchNames, existingPullRequests);\n\n // Perform updates for each of the [targeted] update blocks in dependabot.yaml\n return await this.performUpdates(\n server,\n updates,\n command,\n existingPullRequests,\n dependabotApiUrl,\n dependabotApiDockerUrl,\n );\n } finally {\n server.stop();\n }\n }\n\n /**\n * Abandon all pull requests where the source branch has been deleted.\n * @param existingBranchNames The names of the existing branches.\n * @param existingPullRequests The existing pull requests.\n */\n private async abandonPullRequestsWhereSourceRefIsDeleted(\n existingBranchNames?: string[],\n existingPullRequests?: AzdoPrExtractedWithProperties[],\n ): Promise<void> {\n if (!existingBranchNames || !existingPullRequests) return;\n\n const {\n options: { url, dryRun },\n authorClient,\n } = this;\n for (const pullRequest of existingPullRequests) {\n const pullRequestSourceRefName = normalizeBranchName(\n pullRequest.properties?.find((x) => x.name === PR_PROPERTY_MICROSOFT_GIT_SOURCE_REF_NAME)?.value,\n );\n if (pullRequestSourceRefName && !existingBranchNames.includes(pullRequestSourceRefName)) {\n // The source branch for the pull request has been deleted; abandon the pull request (if not dry run)\n if (!dryRun) {\n logger.warn(\n `Detected source branch for PR #${pullRequest.pullRequestId} has been deleted; The pull request will be abandoned`,\n );\n await authorClient.abandonPullRequest({\n project: url.project,\n repository: url.repository,\n pullRequestId: pullRequest.pullRequestId,\n // comment:\n // 'OK, I won't notify you again about this release, but will get in touch when a new version is available. ' +\n // 'If you'd rather skip all updates until the next major or minor version, add an ' +\n // '[`ignore` condition](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#ignore--) ' +\n // 'with the desired `update-types` to your config file.',\n comment:\n 'It might be a good idea to add an ' +\n '[`ignore` condition](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#ignore--) ' +\n 'with the desired `update-types` to your config file.',\n });\n }\n // Remove the pull request from the list of existing pull requests to ensures that we don't attempt to update it later in the process.\n existingPullRequests.splice(existingPullRequests.indexOf(pullRequest), 1);\n }\n }\n }\n\n /**\n * Performs the updates.\n * @param server The local Dependabot server.\n * @param updates The updates to perform.\n * @param existingPullRequests The existing pull requests.\n */\n private async performUpdates(\n server: AzureLocalDependabotServer,\n updates: DependabotUpdate[],\n command: DependabotCommand,\n existingPullRequests: AzdoPrExtractedWithProperties[],\n dependabotApiUrl: string,\n dependabotApiDockerUrl?: string,\n ): Promise<RunJobsResult> {\n const {\n options: { url, gitToken, githubToken, experiments, config, dryRun, securityAdvisoriesFile, secretMasker },\n } = this;\n\n const results: RunJobsResult = [];\n\n function makeRandomJobId(): string {\n const array = new Uint32Array(1);\n crypto.getRandomValues(array);\n return `${array[0]! % 10000000000}`; // Limit to 10 digits to match GitHub's job IDs\n }\n\n function makeUsageData(job: DependabotJobConfig): RunJobOptions['usage'] {\n return {\n trigger: 'user',\n provider: job.source.provider,\n owner: url.value.toString(),\n project: `${url.value.toString().replace(/\\/$/, '')}/${url.project}`,\n 'package-manager': job['package-manager'],\n };\n }\n\n for (const update of updates) {\n const packageEcosystem = update['package-ecosystem'];\n const packageManager = mapPackageEcosystemToPackageManager(packageEcosystem);\n\n // If there is an updater image, replace the placeholder in it\n let { updaterImage } = this.options;\n updaterImage = updaterImage?.replace(/\\{ecosystem\\}/i, packageEcosystem);\n\n // Parse the Dependabot metadata for the existing pull requests that are related to this update\n // Dependabot will use this to determine if we need to create new pull requests or update/close existing ones\n const existingPullRequestsForPackageManager = parsePullRequestProperties(existingPullRequests, packageManager);\n\n const builder = new DependabotJobBuilder({\n source: { provider: 'azure', ...url },\n config,\n update,\n systemAccessToken: gitToken,\n githubToken,\n experiments,\n debug: false,\n });\n\n let job: DependabotJobConfig | undefined;\n let credentials: DependabotCredential[] | undefined;\n let jobToken: string;\n let credentialsToken: string;\n\n const debug = this.options.debug;\n\n // If this is a security-only update (i.e. 'open-pull-requests-limit: 0'), then we first need to discover the dependencies\n // that need updating and check each one for vulnerabilities. This is because Dependabot requires the list of vulnerable dependencies\n // to be supplied in the job definition of security-only update job, it will not automatically discover them like a versioned update does.\n // https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates#overriding-the-default-behavior-with-a-configuration-file\n const securityVulnerabilities: SecurityVulnerability[] = [];\n const dependencyNamesToUpdate: string[] = [];\n const openPullRequestsLimit = update['open-pull-requests-limit']!;\n const securityUpdatesOnly = openPullRequestsLimit === 0;\n if (securityUpdatesOnly) {\n // Run an update job to discover all dependencies\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forDependenciesList({ id }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n\n const outputs = server.requests(id);\n const packagesToCheckForVulnerabilities: Package[] | undefined = outputs!\n .find((o) => o.type === 'update_dependency_list')\n ?.data.dependencies?.map((d) => ({ name: d.name, version: d.version }));\n if (packagesToCheckForVulnerabilities?.length) {\n logger.info(\n `Detected ${packagesToCheckForVulnerabilities.length} dependencies; Checking for vulnerabilities...`,\n );\n\n // parse security advisories from file (private)\n if (securityAdvisoriesFile) {\n const filePath = securityAdvisoriesFile;\n if (existsSync(filePath)) {\n const fileContents = await readFile(filePath, 'utf-8');\n securityVulnerabilities.push(\n ...(await SecurityVulnerabilitySchema.array().parseAsync(JSON.parse(fileContents))),\n );\n } else {\n logger.info(`Private security advisories file '${filePath}' does not exist`);\n }\n }\n if (githubToken) {\n const ghsaClient = new GitHubSecurityAdvisoryClient(githubToken);\n const githubVulnerabilities = await ghsaClient.getSecurityVulnerabilitiesAsync(\n getGhsaPackageEcosystemFromDependabotPackageManager(packageManager),\n packagesToCheckForVulnerabilities || [],\n );\n securityVulnerabilities.push(...githubVulnerabilities);\n } else {\n logger.info(\n 'GitHub access token is not provided; Checking for vulnerabilities from GitHub is skipped. ' +\n 'This is not an issue if you are using private security advisories file.',\n );\n }\n\n const filtered = filterVulnerabilities(securityVulnerabilities);\n securityVulnerabilities.splice(0); // clear array\n securityVulnerabilities.push(...filtered);\n\n // Only update dependencies that have vulnerabilities\n dependencyNamesToUpdate.push(...Array.from(new Set(securityVulnerabilities.map((v) => v.package.name))));\n logger.info(\n `Detected ${securityVulnerabilities.length} vulnerabilities affecting ${dependencyNamesToUpdate.length} dependencies`,\n );\n if (dependencyNamesToUpdate.length) {\n logger.trace(dependencyNamesToUpdate);\n }\n } else {\n logger.info(`No vulnerabilities detected for update ${update['package-ecosystem']} in ${update.directory}`);\n server.clear(id);\n continue; // nothing more to do for this update\n }\n\n server.clear(id);\n }\n\n // Run an update job for \"all dependencies\"; this will create new pull requests for dependencies that need updating\n const openPullRequestsCount = existingPullRequestsForPackageManager.length;\n const hasReachedOpenPullRequestLimit =\n openPullRequestsLimit > 0 && openPullRequestsCount >= openPullRequestsLimit;\n if (!hasReachedOpenPullRequestLimit) {\n const dependenciesHaveVulnerabilities = dependencyNamesToUpdate.length && securityVulnerabilities.length;\n if (!securityUpdatesOnly || dependenciesHaveVulnerabilities) {\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forUpdate({\n id,\n command,\n dependencyNamesToUpdate,\n existingPullRequests: existingPullRequestsForPackageManager,\n securityVulnerabilities,\n }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n const { success, message } = await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n const affectedPrs = server.allAffectedPrs(id);\n server.clear(id);\n results.push({ id, success, message, affectedPrs });\n } else {\n logger.info('Nothing to update; dependencies are not affected by any known vulnerability');\n }\n } else {\n logger.warn(\n `Skipping update for ${packageEcosystem} packages as the open pull requests limit (${openPullRequestsLimit}) has already been reached`,\n );\n }\n\n // If there are existing pull requests, run an update job for each one; this will resolve merge conflicts and close pull requests that are no longer needed\n const numberOfPullRequestsToUpdate = existingPullRequestsForPackageManager.length;\n if (numberOfPullRequestsToUpdate > 0) {\n if (!dryRun) {\n for (const pullRequestToUpdate of existingPullRequestsForPackageManager) {\n const id = makeRandomJobId();\n ({ job, credentials } = builder.forUpdate({\n id,\n command,\n existingPullRequests: existingPullRequestsForPackageManager,\n pullRequestToUpdate,\n securityVulnerabilities,\n }));\n ({ jobToken, credentialsToken } = this.makeTokens());\n server.add({ id, update, job, jobToken, credentialsToken, credentials });\n const { success, message } = await runJob({\n dependabotApiUrl,\n dependabotApiDockerUrl,\n jobId: id,\n jobToken,\n credentialsToken,\n updaterImage,\n secretMasker,\n debug,\n usage: makeUsageData(job),\n });\n const affectedPrs = server.allAffectedPrs(id);\n server.clear(id);\n results.push({ id, success, message, affectedPrs });\n }\n } else {\n logger.warn(\n `Skipping update of ${numberOfPullRequestsToUpdate} existing ${packageEcosystem} package pull request(s) as 'dryRun' is set to 'true'`,\n );\n }\n }\n }\n\n return results;\n }\n}\n"],"mappings":"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"}
|
package/dist/local/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "../api-client-
|
|
2
|
-
import { a as LocalJobsRunner, i as LocalDependabotServerOptions, n as LocalDependabotServer, o as LocalJobsRunnerOptions, r as LocalDependabotServerAddOptions, s as RunJobsResult, t as AffectedPullRequestIds } from "../server-
|
|
1
|
+
import "../api-client-DZQQArbU.mjs";
|
|
2
|
+
import { a as LocalJobsRunner, i as LocalDependabotServerOptions, n as LocalDependabotServer, o as LocalJobsRunnerOptions, r as LocalDependabotServerAddOptions, s as RunJobsResult, t as AffectedPullRequestIds } from "../server-B6aYEkTC.mjs";
|
|
3
3
|
export { AffectedPullRequestIds, LocalDependabotServer, LocalDependabotServerAddOptions, LocalDependabotServerOptions, LocalJobsRunner, LocalJobsRunnerOptions, RunJobsResult };
|
package/dist/local/index.mjs
CHANGED
|
@@ -104,7 +104,7 @@ var ApiClient = class {
|
|
|
104
104
|
return await this.client.get(url, {
|
|
105
105
|
headers: { Authorization: token },
|
|
106
106
|
retry: { limit: 3 },
|
|
107
|
-
hooks: { beforeRetry: [async ({ request, options
|
|
107
|
+
hooks: { beforeRetry: [async ({ request, options, error, retryCount }) => {
|
|
108
108
|
if (isHTTPError(error)) logger.warn(`Retrying failed request with status code: ${error.response.status}`);
|
|
109
109
|
}] },
|
|
110
110
|
...options
|
|
@@ -116,38 +116,38 @@ var ApiClient = class {
|
|
|
116
116
|
|
|
117
117
|
//#endregion
|
|
118
118
|
//#region docker/containers.json
|
|
119
|
-
var proxy = "ghcr.io/
|
|
119
|
+
var proxy = "ghcr.io/dependabot/proxy:v2.0.20260208213134@sha256:8d48998df972a1c696cadf1cafebacd3513bde3444ccec2207098e6aef5fd10a";
|
|
120
120
|
var containers_default = {
|
|
121
121
|
proxy,
|
|
122
|
-
bundler: "ghcr.io/dependabot/dependabot-updater-bundler:v2.0.
|
|
123
|
-
cargo: "ghcr.io/dependabot/dependabot-updater-cargo:v2.0.
|
|
124
|
-
composer: "ghcr.io/dependabot/dependabot-updater-composer:v2.0.
|
|
125
|
-
conda: "ghcr.io/dependabot/dependabot-updater-conda:v2.0.
|
|
126
|
-
pub: "ghcr.io/dependabot/dependabot-updater-pub:v2.0.
|
|
127
|
-
docker: "ghcr.io/dependabot/dependabot-updater-docker:v2.0.
|
|
128
|
-
elm: "ghcr.io/dependabot/dependabot-updater-elm:v2.0.
|
|
129
|
-
github_actions: "ghcr.io/dependabot/dependabot-updater-github-actions:v2.0.
|
|
130
|
-
submodules: "ghcr.io/dependabot/dependabot-updater-gitsubmodule:v2.0.
|
|
131
|
-
go_modules: "ghcr.io/dependabot/dependabot-updater-gomod:v2.0.
|
|
132
|
-
gradle: "ghcr.io/dependabot/dependabot-updater-gradle:v2.0.
|
|
133
|
-
maven: "ghcr.io/dependabot/dependabot-updater-maven:v2.0.
|
|
134
|
-
hex: "ghcr.io/dependabot/dependabot-updater-mix:v2.0.
|
|
135
|
-
nuget: "ghcr.io/dependabot/dependabot-updater-nuget:v2.0.
|
|
136
|
-
npm_and_yarn: "ghcr.io/dependabot/dependabot-updater-npm:v2.0.
|
|
137
|
-
pip: "ghcr.io/dependabot/dependabot-updater-pip:v2.0.
|
|
138
|
-
rust_toolchain: "ghcr.io/dependabot/dependabot-updater-rust-toolchain:v2.0.
|
|
139
|
-
swift: "ghcr.io/dependabot/dependabot-updater-swift:v2.0.
|
|
140
|
-
terraform: "ghcr.io/dependabot/dependabot-updater-terraform:v2.0.
|
|
141
|
-
devcontainers: "ghcr.io/dependabot/dependabot-updater-devcontainers:v2.0.
|
|
142
|
-
dotnet_sdk: "ghcr.io/dependabot/dependabot-updater-dotnet-sdk:v2.0.
|
|
143
|
-
bun: "ghcr.io/dependabot/dependabot-updater-bun:v2.0.
|
|
144
|
-
docker_compose: "ghcr.io/dependabot/dependabot-updater-docker-compose:v2.0.
|
|
145
|
-
uv: "ghcr.io/dependabot/dependabot-updater-uv:v2.0.
|
|
146
|
-
vcpkg: "ghcr.io/dependabot/dependabot-updater-vcpkg:v2.0.
|
|
147
|
-
helm: "ghcr.io/dependabot/dependabot-updater-helm:v2.0.
|
|
148
|
-
julia: "ghcr.io/dependabot/dependabot-updater-julia:v2.0.
|
|
149
|
-
bazel: "ghcr.io/dependabot/dependabot-updater-bazel:v2.0.
|
|
150
|
-
opentofu: "ghcr.io/dependabot/dependabot-updater-opentofu:v2.0.
|
|
122
|
+
bundler: "ghcr.io/dependabot/dependabot-updater-bundler:v2.0.20260206190242@sha256:89667874b9265bb9bc1dd8d8baabf924d946b067a4785a86d99e01c0f696a632",
|
|
123
|
+
cargo: "ghcr.io/dependabot/dependabot-updater-cargo:v2.0.20260206190242@sha256:b40b95fed633563e1087f79d2cd9b86035541361b0d426f33c531d375cef716a",
|
|
124
|
+
composer: "ghcr.io/dependabot/dependabot-updater-composer:v2.0.20260206190242@sha256:e920dd7ea63df9fa15a3c9308eb7eb3eba3b0a97c653924db8f0fc67c547e534",
|
|
125
|
+
conda: "ghcr.io/dependabot/dependabot-updater-conda:v2.0.20260206190242@sha256:84e1af373e87eecac9ab49a0c71e6d1247b01362bced701ab98b16c2b1ee2276",
|
|
126
|
+
pub: "ghcr.io/dependabot/dependabot-updater-pub:v2.0.20260206190242@sha256:540b1aa53fbdc7e5e32333e7a1d05d5dd9984a5ac271ee54d0a41fa754d9070b",
|
|
127
|
+
docker: "ghcr.io/dependabot/dependabot-updater-docker:v2.0.20260206190242@sha256:f2f0601ffbff5257b39016efec6cc3694bfdcd84ec2787410d59f0c2c664dc25",
|
|
128
|
+
elm: "ghcr.io/dependabot/dependabot-updater-elm:v2.0.20260206190242@sha256:a3f68b2654485d067c9ff27cd0e23fe3733107e1cb3f1a5086d599651ece5699",
|
|
129
|
+
github_actions: "ghcr.io/dependabot/dependabot-updater-github-actions:v2.0.20260206190242@sha256:1c41897c800e9afc2a1d94bf0326a5f643b3abd8c65c1372b3e251a67e5b60fe",
|
|
130
|
+
submodules: "ghcr.io/dependabot/dependabot-updater-gitsubmodule:v2.0.20260206190242@sha256:4913c9ce6e50219c4bf3d7d43d735f3f06c0a0c056e2884bf36f1fae1fff7c5f",
|
|
131
|
+
go_modules: "ghcr.io/dependabot/dependabot-updater-gomod:v2.0.20260206190242@sha256:76b2754dc318a52ca5899ba4713456e12825ceb5328b526bac04521e87979afb",
|
|
132
|
+
gradle: "ghcr.io/dependabot/dependabot-updater-gradle:v2.0.20260206190242@sha256:04ef305e5235c09d85db58b6ea6815c46b656ca33aae26ecedf19b742b8b57d6",
|
|
133
|
+
maven: "ghcr.io/dependabot/dependabot-updater-maven:v2.0.20260206190242@sha256:2ce46802c36c27e33234ee19249f272fb9e31b3d8b983177361f631e9d1beb49",
|
|
134
|
+
hex: "ghcr.io/dependabot/dependabot-updater-mix:v2.0.20260206190242@sha256:3e7389708a3eb586aa621707fd1f2a5a0f00d49438e8b580053d5147e8cd5801",
|
|
135
|
+
nuget: "ghcr.io/dependabot/dependabot-updater-nuget:v2.0.20260206190242@sha256:24a36b7e07c6dcc0a46371b32455235a4fda590a149ce578181c69a0f27d67ad",
|
|
136
|
+
npm_and_yarn: "ghcr.io/dependabot/dependabot-updater-npm:v2.0.20260206190242@sha256:7f612e29b39b9fa9407d563b1ed16c0003c3bb5d2e2cc04aeb2ccc2481da6190",
|
|
137
|
+
pip: "ghcr.io/dependabot/dependabot-updater-pip:v2.0.20260206190242@sha256:67d02c5b84cfbfc497be378924543ee07fd9b563718ac881939353adec22bbc4",
|
|
138
|
+
rust_toolchain: "ghcr.io/dependabot/dependabot-updater-rust-toolchain:v2.0.20260206190242@sha256:95caec822f8192526a1f7a4c6b617bce9a3b11dc617d40cc3e50f7193b9decdb",
|
|
139
|
+
swift: "ghcr.io/dependabot/dependabot-updater-swift:v2.0.20260206190242@sha256:35794f92d0f8d0399e49c36a25295d9de18efdb42877d9ab6284056b2e1c60f5",
|
|
140
|
+
terraform: "ghcr.io/dependabot/dependabot-updater-terraform:v2.0.20260206190242@sha256:aca76af64410eedd71cf77416866668a61a399d2381ba2e0ae621a39197b6b19",
|
|
141
|
+
devcontainers: "ghcr.io/dependabot/dependabot-updater-devcontainers:v2.0.20260206190242@sha256:4fbaaf73251bcdd1061e62ed1f01aed51d67676221b6c1c0fddbb81efe9f92e3",
|
|
142
|
+
dotnet_sdk: "ghcr.io/dependabot/dependabot-updater-dotnet-sdk:v2.0.20260206190242@sha256:0ed30c9ab17c0a302a020e63244dad9d2d7989d7478db07a63a0777f36c767ff",
|
|
143
|
+
bun: "ghcr.io/dependabot/dependabot-updater-bun:v2.0.20260206190242@sha256:f2a8c2b865f88312faef3874a81b5a2b7f60ba14b56244b45c2c194b319bdd72",
|
|
144
|
+
docker_compose: "ghcr.io/dependabot/dependabot-updater-docker-compose:v2.0.20260206190242@sha256:b3cae22b3a485219493cbb7b09d2f4a9467652bb0af51c897ae47c7a322d2e35",
|
|
145
|
+
uv: "ghcr.io/dependabot/dependabot-updater-uv:v2.0.20260206190242@sha256:e04f3c74e3962a845009b7a49a735d0ed1d65ad4ec8fdd60466ad610b821428f",
|
|
146
|
+
vcpkg: "ghcr.io/dependabot/dependabot-updater-vcpkg:v2.0.20260206190242@sha256:2cfa8dbebef516f90a489d5dabbfb98fbc1481c7cabe093ab6ffb0f3fde64c03",
|
|
147
|
+
helm: "ghcr.io/dependabot/dependabot-updater-helm:v2.0.20260206190242@sha256:e704319f42b10d024278c3e83702afccac33a11ca2158fbeb50c3eb192f6c850",
|
|
148
|
+
julia: "ghcr.io/dependabot/dependabot-updater-julia:v2.0.20260206190242@sha256:e047949ac33974549f894977954ab32a0d4070f6143f812a1612651bc09f88a0",
|
|
149
|
+
bazel: "ghcr.io/dependabot/dependabot-updater-bazel:v2.0.20260206190242@sha256:d13cf6a7c60b2d0177a068c61f9ab2ff8de73631c9bdb4dd986aaf782617eae6",
|
|
150
|
+
opentofu: "ghcr.io/dependabot/dependabot-updater-opentofu:v2.0.20260206190242@sha256:586532d27ed8012286aee7a6490c631527896d99e2b6de3fae3d3c311244a856"
|
|
151
151
|
};
|
|
152
152
|
|
|
153
153
|
//#endregion
|
|
@@ -265,13 +265,13 @@ const ContainerService = {
|
|
|
265
265
|
AttachStdout: true,
|
|
266
266
|
AttachStderr: true
|
|
267
267
|
});
|
|
268
|
-
const stream
|
|
268
|
+
const stream = await exec.start({});
|
|
269
269
|
await new Promise((resolve, reject) => {
|
|
270
|
-
container.modem.demuxStream(stream
|
|
271
|
-
stream
|
|
270
|
+
container.modem.demuxStream(stream, outStream("updater"), errStream("updater"));
|
|
271
|
+
stream.on("end", () => {
|
|
272
272
|
resolve();
|
|
273
273
|
});
|
|
274
|
-
stream
|
|
274
|
+
stream.on("error", (error) => {
|
|
275
275
|
reject(error);
|
|
276
276
|
});
|
|
277
277
|
});
|
|
@@ -286,9 +286,9 @@ const ContainerService = {
|
|
|
286
286
|
const MAX_RETRIES = 5;
|
|
287
287
|
const INITIAL_DELAY_MS = 5e3;
|
|
288
288
|
const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
289
|
-
const endOfStream = async (docker
|
|
289
|
+
const endOfStream = async (docker, stream) => {
|
|
290
290
|
return new Promise((resolve, reject) => {
|
|
291
|
-
docker
|
|
291
|
+
docker.modem.followProgress(stream, (err) => err ? reject(err) : resolve(void 0));
|
|
292
292
|
});
|
|
293
293
|
};
|
|
294
294
|
function getOrgFromImage(imageName) {
|
|
@@ -300,10 +300,10 @@ function getOrgFromImage(imageName) {
|
|
|
300
300
|
const ImageService = {
|
|
301
301
|
async pull(imageName, sendMetric, force = false) {
|
|
302
302
|
if (!(imageName.startsWith("ghcr.io/") || imageName.startsWith("docker.pkg.github.com/"))) throw new Error("Only images distributed via docker.pkg.github.com or ghcr.io can be fetched");
|
|
303
|
-
const docker
|
|
303
|
+
const docker = new Docker();
|
|
304
304
|
const org = getOrgFromImage(imageName);
|
|
305
305
|
try {
|
|
306
|
-
const image = await docker
|
|
306
|
+
const image = await docker.getImage(imageName).inspect();
|
|
307
307
|
if (!force) {
|
|
308
308
|
logger.info(`Resolved ${imageName} to existing ${image.RepoDigests}`);
|
|
309
309
|
return;
|
|
@@ -311,15 +311,15 @@ const ImageService = {
|
|
|
311
311
|
} catch (e) {
|
|
312
312
|
if (e instanceof Error && !e.message.includes("no such image")) throw e;
|
|
313
313
|
}
|
|
314
|
-
await this.fetchImageWithRetry(imageName, {}, docker
|
|
314
|
+
await this.fetchImageWithRetry(imageName, {}, docker, sendMetric, org);
|
|
315
315
|
},
|
|
316
|
-
async fetchImageWithRetry(imageName, auth = {}, docker
|
|
316
|
+
async fetchImageWithRetry(imageName, auth = {}, docker = new Docker(), sendMetric, org) {
|
|
317
317
|
let attempt = 0;
|
|
318
318
|
while (attempt < MAX_RETRIES) try {
|
|
319
319
|
logger.info(`Pulling image ${imageName} (attempt ${attempt + 1})...`);
|
|
320
320
|
if (sendMetric) await sendMetric("ghcr_image_pull", "increment", 1, { org });
|
|
321
|
-
const stream
|
|
322
|
-
await endOfStream(docker
|
|
321
|
+
const stream = await docker.pull(imageName, { authconfig: auth });
|
|
322
|
+
await endOfStream(docker, new Readable().wrap(stream));
|
|
323
323
|
logger.info(`Pulled image ${imageName}`);
|
|
324
324
|
return;
|
|
325
325
|
} catch (error) {
|
|
@@ -394,8 +394,8 @@ const CERT_SUBJECT = [
|
|
|
394
394
|
}
|
|
395
395
|
];
|
|
396
396
|
var ProxyBuilder = class ProxyBuilder {
|
|
397
|
-
constructor(docker
|
|
398
|
-
this.docker = docker
|
|
397
|
+
constructor(docker, proxyImage, cachedMode, debug) {
|
|
398
|
+
this.docker = docker;
|
|
399
399
|
this.proxyImage = proxyImage;
|
|
400
400
|
this.cachedMode = cachedMode;
|
|
401
401
|
this.debug = debug;
|
|
@@ -416,12 +416,12 @@ var ProxyBuilder = class ProxyBuilder {
|
|
|
416
416
|
const customCert = (await readFile(customCAPath, "utf8")).toString();
|
|
417
417
|
await ContainerService.storeCert(CUSTOM_CA_CERT_NAME, CA_CERT_INPUT_PATH$1, container, customCert);
|
|
418
418
|
}
|
|
419
|
-
const stream
|
|
419
|
+
const stream = await container.attach({
|
|
420
420
|
stream: true,
|
|
421
421
|
stdout: true,
|
|
422
422
|
stderr: true
|
|
423
423
|
});
|
|
424
|
-
container.modem.demuxStream(stream
|
|
424
|
+
container.modem.demuxStream(stream, this.debug ? outStream(" proxy") : nullStream, this.debug ? errStream(" proxy") : nullStream);
|
|
425
425
|
const url = async () => {
|
|
426
426
|
const containerInfo = await container.inspect();
|
|
427
427
|
if (containerInfo.State.Running === true) return `http://${containerInfo.NetworkSettings.Networks[`${internalNetworkName}`].IPAddress}:1080`;
|
|
@@ -537,7 +537,7 @@ var ProxyBuilder = class ProxyBuilder {
|
|
|
537
537
|
|
|
538
538
|
//#endregion
|
|
539
539
|
//#region package.json
|
|
540
|
-
var version = "0.
|
|
540
|
+
var version = "0.11.0";
|
|
541
541
|
|
|
542
542
|
//#endregion
|
|
543
543
|
//#region src/updater-builder.ts
|
|
@@ -548,11 +548,11 @@ const CA_CERT_INPUT_PATH = "/usr/local/share/ca-certificates";
|
|
|
548
548
|
const CA_CERT_FILENAME = "dbot-ca.crt";
|
|
549
549
|
const UPDATER_MAX_MEMORY = 8 * 1024 * 1024 * 1024;
|
|
550
550
|
var UpdaterBuilder = class {
|
|
551
|
-
constructor(docker
|
|
552
|
-
this.docker = docker
|
|
551
|
+
constructor(docker, jobParams, input, proxy, updaterImage) {
|
|
552
|
+
this.docker = docker;
|
|
553
553
|
this.jobParams = jobParams;
|
|
554
554
|
this.input = input;
|
|
555
|
-
this.proxy = proxy
|
|
555
|
+
this.proxy = proxy;
|
|
556
556
|
this.updaterImage = updaterImage;
|
|
557
557
|
}
|
|
558
558
|
async run(containerName) {
|
|
@@ -615,13 +615,13 @@ var Updater = class {
|
|
|
615
615
|
*/
|
|
616
616
|
async runUpdater() {
|
|
617
617
|
const cachedMode = Object.hasOwn(this.job.experiments, "proxy-cached") === true;
|
|
618
|
-
const proxy
|
|
619
|
-
await proxy
|
|
618
|
+
const proxy = await new ProxyBuilder(this.docker, this.proxyImage, cachedMode, this.debug).run(this.params.jobId, this.params.jobToken, this.params.dependabotApiUrl, this.credentials);
|
|
619
|
+
await proxy.container.start();
|
|
620
620
|
try {
|
|
621
|
-
await this.runUpdate(proxy
|
|
621
|
+
await this.runUpdate(proxy);
|
|
622
622
|
return true;
|
|
623
623
|
} finally {
|
|
624
|
-
await this.cleanup(proxy
|
|
624
|
+
await this.cleanup(proxy);
|
|
625
625
|
}
|
|
626
626
|
}
|
|
627
627
|
generateCredentialsMetadata() {
|
|
@@ -668,16 +668,16 @@ var Updater = class {
|
|
|
668
668
|
obj["index-url"] = credential.url;
|
|
669
669
|
} catch {}
|
|
670
670
|
}
|
|
671
|
-
async runUpdate(proxy
|
|
671
|
+
async runUpdate(proxy) {
|
|
672
672
|
const name = `dependabot-job-${this.params.jobId}`;
|
|
673
|
-
const container = await this.createContainer(proxy
|
|
673
|
+
const container = await this.createContainer(proxy, name, { job: this.job });
|
|
674
674
|
await ContainerService.run(container, this.job.command);
|
|
675
675
|
}
|
|
676
|
-
async createContainer(proxy
|
|
677
|
-
return new UpdaterBuilder(this.docker, this.params, input, proxy
|
|
676
|
+
async createContainer(proxy, containerName, input) {
|
|
677
|
+
return new UpdaterBuilder(this.docker, this.params, input, proxy, this.updaterImage).run(containerName);
|
|
678
678
|
}
|
|
679
|
-
async cleanup(proxy
|
|
680
|
-
await proxy
|
|
679
|
+
async cleanup(proxy) {
|
|
680
|
+
await proxy.shutdown();
|
|
681
681
|
}
|
|
682
682
|
};
|
|
683
683
|
|
|
@@ -783,4 +783,4 @@ async function isRunningInDocker() {
|
|
|
783
783
|
|
|
784
784
|
//#endregion
|
|
785
785
|
export { hasDigest as C, ApiClient as D, updaterImages as E, CredentialFetchingError as O, digestName as S, updaterImageName as T, getOrgFromImage as _, Updater as a, extractUpdaterSha as b, JOB_INPUT_FILENAME as c, UpdaterBuilder as d, CONFIG_FILE_NAME as f, ImageService as g, getJobParameters as h, runJob as i, JobDetailsFetchingError as k, JOB_INPUT_PATH as l, JobParameters as m, JobRunnerUpdaterError as n, CA_CERT_FILENAME as o, ProxyBuilder as p, isRunningInDocker as r, CA_CERT_INPUT_PATH as s, JobRunnerImagingError as t, REPO_CONTENTS_PATH as u, ContainerRuntimeError as v, repositoryName as w, PROXY_IMAGE_NAME as x, ContainerService as y };
|
|
786
|
-
//# sourceMappingURL=run-
|
|
786
|
+
//# sourceMappingURL=run-DLJ0FJ4t.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-DLJ0FJ4t.mjs","names":["dockerContainerConfig.proxy","dockerContainerConfig","CA_CERT_INPUT_PATH","packageJson.version"],"sources":["../src/api-client.ts","../docker/containers.json","../src/docker-tags.ts","../src/utils.ts","../src/container-service.ts","../src/image-service.ts","../src/params.ts","../src/proxy.ts","../package.json","../src/updater-builder.ts","../src/updater.ts","../src/run.ts"],"sourcesContent":["import type {\n DependabotCredential,\n DependabotJobConfig,\n DependabotMetric,\n DependabotRecordUpdateJobError,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport { isHTTPError, type KyInstance, type KyResponse } from 'ky';\nimport type { JobParameters } from './params';\n\nexport class JobDetailsFetchingError extends Error {}\nexport class CredentialFetchingError extends Error {}\nexport type SecretMasker = (value: string) => void;\n\nexport class ApiClient {\n private dependabotApiUrl: string;\n private jobToken: string;\n constructor(\n private readonly client: KyInstance,\n readonly params: JobParameters,\n jobToken: string,\n private readonly credentialsToken: string,\n private readonly secretMasker: SecretMasker,\n ) {\n // if dependabotApiUrl contains \"host.docker.internal\", we need to replace it with \"localhost\" for local calls\n const baseUrl = params.dependabotApiUrl.replace('host.docker.internal', 'localhost');\n this.dependabotApiUrl = baseUrl;\n this.jobToken = jobToken;\n }\n\n // We use a static unknown SHA when marking a job as complete from the action\n // to remain in parity with the existing runner.\n UnknownSha = {\n 'base-commit-sha': 'unknown',\n };\n\n // Getter for jobToken\n getJobToken(): string {\n return this.jobToken;\n }\n\n async getJobDetails(): Promise<DependabotJobConfig> {\n const detailsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/details`;\n try {\n const res = await this.getWithRetry<DependabotJobConfig>(detailsURL, this.jobToken);\n if (res.status !== 200) {\n throw new JobDetailsFetchingError(\n `fetching job details: unexpected status code: ${res.status}: ${JSON.stringify(await res.json())}`,\n );\n }\n const data = await res.json();\n if (!data) {\n throw new JobDetailsFetchingError(`fetching job details: missing response`);\n }\n\n return data;\n } catch (error) {\n if (error instanceof JobDetailsFetchingError) {\n throw error;\n } else if (isHTTPError(error)) {\n throw new JobDetailsFetchingError(\n `fetching job details: unexpected status code: ${error.response.status}: ${error.message}`,\n );\n } else if (error instanceof Error) {\n throw new JobDetailsFetchingError(`fetching job details: ${error.name}: ${error.message}`);\n }\n throw error;\n }\n }\n\n async getCredentials(): Promise<DependabotCredential[]> {\n const credentialsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/credentials`;\n try {\n const res = await this.getWithRetry<DependabotCredential[]>(credentialsURL, this.credentialsToken);\n\n if (res.status !== 200) {\n throw new CredentialFetchingError(\n `fetching credentials: unexpected status code: ${res.status}: ${JSON.stringify(await res.json())}`,\n );\n }\n const data = await res.json();\n if (!data) {\n throw new CredentialFetchingError(`fetching credentials: missing response`);\n }\n\n // Mask any secrets we've just retrieved from environment logs\n for (const credential of data) {\n if (credential.password) {\n this.secretMasker(credential.password);\n }\n if (credential.token) {\n this.secretMasker(credential.token);\n }\n if (credential['auth-key']) {\n this.secretMasker(credential['auth-key']);\n }\n }\n\n return data;\n } catch (error: unknown) {\n if (error instanceof CredentialFetchingError) {\n throw error;\n } else if (isHTTPError(error)) {\n throw new CredentialFetchingError(\n `fetching credentials: unexpected status code: ${error.response.status}: ${error.message}`,\n );\n } else if (error instanceof Error) {\n throw new CredentialFetchingError(`fetching credentials: ${error.name}: ${error.message}`);\n }\n throw error;\n }\n }\n\n async reportJobError(error: DependabotRecordUpdateJobError): Promise<void> {\n const recordErrorURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/record_update_job_error`;\n const res = await this.client.post(recordErrorURL, {\n json: error,\n headers: { Authorization: this.jobToken },\n });\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n async markJobAsProcessed(): Promise<void> {\n const markAsProcessedURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/mark_as_processed`;\n const res = await this.client.patch(markAsProcessedURL, {\n json: this.UnknownSha,\n headers: { Authorization: this.jobToken },\n });\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n async sendMetrics(\n name: string,\n metricType: 'increment' | 'gauge',\n value: number,\n additionalTags: Record<string, string> = {},\n ): Promise<void> {\n try {\n await this.reportMetrics([\n {\n metric: `dependabot.action.${name}`,\n type: metricType,\n value,\n tags: additionalTags,\n },\n ]);\n logger.info(`Successfully sent metric (dependabot.action.${name}) to remote API endpoint`);\n } catch (error) {\n // metrics should typically not cause critical path failure so we log the\n // failure and continue with the job\n logger.warn(`Metrics reporting failed: ${(error as Error).message}`);\n }\n }\n\n async reportMetrics(metrics: DependabotMetric[]): Promise<void> {\n const metricsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/record_metrics`;\n const res = await this.client.post(metricsURL, {\n json: { data: metrics },\n headers: { Authorization: this.jobToken },\n });\n\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n private async getWithRetry<T>(url: string, token: string, options?: RequestInit): Promise<KyResponse<T>> {\n const execute = async (): Promise<KyResponse<T>> => {\n const res = await this.client.get<T>(url, {\n headers: { Authorization: token },\n retry: {\n limit: 3,\n // other default options are sufficient:\n // https://github.com/sindresorhus/ky#retry\n // delay: attemptCount => 0.3 * (2 ** (attemptCount - 1)) * 1000\n // statusCodes: 408 413 429 500 502 503 504\n // afterStatusCodes: 413, 429, 503\n },\n hooks: {\n beforeRetry: [\n async ({ request, options, error, retryCount }) => {\n if (isHTTPError(error)) {\n logger.warn(`Retrying failed request with status code: ${error.response.status}`);\n }\n },\n ],\n },\n ...options,\n });\n\n return res;\n };\n\n return execute();\n }\n}\n","","import dockerContainerConfig from '../docker/containers.json';\n\nexport const PROXY_IMAGE_NAME = dockerContainerConfig.proxy;\n\nexport function updaterImageName(packageManager: string): string {\n return dockerContainerConfig[packageManager as keyof typeof dockerContainerConfig];\n}\n\nconst updaterRegex = /ghcr.io\\/dependabot\\/dependabot-updater-([\\w+])/;\n\nexport function updaterImages(): string[] {\n return Object.values(dockerContainerConfig).filter((image) => image.match(updaterRegex));\n}\n\nconst imageNamePattern =\n '^(?<repository>(([a-zA-Z0-9._-]+([:[0-9]+[^/]))?([a-zA-Z0-9._/-]+)?))(:[a-zA-Z0-9._/-]+)?(?<digest>@sha256:[a-zA-Z0-9]{64})?$';\n\nexport function repositoryName(imageName: string): string {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n return match.groups.repository!;\n } else {\n throw Error('invalid image name');\n }\n}\n\nexport function hasDigest(imageName: string): boolean {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n if (match?.groups.digest) {\n return true;\n }\n return false;\n } else {\n throw Error('invalid image name');\n }\n}\n\nexport function digestName(imageName: string): string {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n return match.groups.repository! + match.groups.digest;\n } else {\n throw Error('invalid image name');\n }\n}\n","import stream, { type Writable } from 'node:stream';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport const nullStream: Writable = new stream.Writable({ write: (__, _, next) => next() });\n\nexport const outStream = (prefix: string): Writable => {\n return new stream.Writable({\n write(chunk, _, next) {\n process.stdout.write(`${prefix} | ${chunk.toString()}`);\n next();\n },\n });\n};\n\nexport const errStream = (prefix: string): Writable => {\n return new stream.Writable({\n write(chunk, _, next) {\n process.stderr.write(`${prefix} | ${chunk.toString()}`);\n next();\n },\n });\n};\n\n/**\n * Extracts the SHA from an updater image string.\n * @param updaterImage - Image string in the format \"image:sha\" or \"registry/image:sha\"\n * @returns The SHA part after the last colon, or null if no colon is found\n */\nexport const extractUpdaterSha = (updaterImage: string): string | null => {\n const match = updaterImage.match(/:([^:]*)$/);\n return match ? match[1]! : null;\n};\n","import type { DependabotProxyConfig, FileFetcherInput, FileUpdaterInput } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type { Container } from 'dockerode';\nimport { pack } from 'tar-stream';\nimport { errStream, outStream } from './utils';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class ContainerRuntimeError extends Error {}\n\nconst RWX_ALL = 0o777;\n\nexport const ContainerService = {\n async storeInput(\n name: string,\n path: string,\n container: Container,\n input: FileFetcherInput | FileUpdaterInput | DependabotProxyConfig,\n ): Promise<void> {\n const tar = pack();\n tar.entry({ name, mode: RWX_ALL }, JSON.stringify(input));\n tar.finalize();\n await container.putArchive(tar, { path });\n },\n\n async storeCert(name: string, path: string, container: Container, cert: string): Promise<void> {\n const tar = pack();\n tar.entry({ name }, cert);\n tar.finalize();\n await container.putArchive(tar, { path });\n },\n\n async run(container: Container, command?: string): Promise<boolean> {\n try {\n // Start the container\n await container.start();\n logger.info(`Started container ${container.id}`);\n\n // Check if this is a dependabot container (has the expected structure)\n const containerInfo = await container.inspect();\n const isDependabotContainer = containerInfo.Config?.Env?.some((env) => env.startsWith('DEPENDABOT_JOB_ID='));\n\n if (isDependabotContainer) {\n // For dependabot containers, run CA certificates update as root first\n await this.execCommand(container, ['/usr/sbin/update-ca-certificates'], 'root');\n\n // Then run the dependabot commands as dependabot user\n const dependabotCommands = [\n 'mkdir -p /home/dependabot/dependabot-updater/output',\n // 'fetch_files' command removed as it is now a no-op\n ];\n\n if (command === 'graph') {\n dependabotCommands.push('$DEPENDABOT_HOME/dependabot-updater/bin/run update_graph');\n } else {\n dependabotCommands.push('$DEPENDABOT_HOME/dependabot-updater/bin/run update_files');\n }\n\n for (const cmd of dependabotCommands) {\n await this.execCommand(container, ['/bin/sh', '-c', cmd], 'dependabot');\n }\n } else {\n // For test containers and other containers, just wait for completion\n const outcome = await container.wait();\n if (outcome.StatusCode !== 0) {\n throw new Error(`Container exited with code ${outcome.StatusCode}`);\n }\n }\n\n return true;\n } catch (error) {\n logger.info(`Failure running container ${container.id}: ${error}`);\n throw new ContainerRuntimeError('The updater encountered one or more errors.');\n } finally {\n try {\n await container.remove({ v: true, force: true });\n logger.info(`Cleaned up container ${container.id}`);\n } catch (error) {\n logger.info(`Failed to clean up container ${container.id}: ${error}`);\n }\n }\n },\n\n async execCommand(container: Container, cmd: string[], user: string): Promise<void> {\n const exec = await container.exec({\n Cmd: cmd,\n User: user,\n AttachStdout: true,\n AttachStderr: true,\n });\n\n const stream = await exec.start({});\n\n // Wait for the stream to end\n await new Promise<void>((resolve, reject) => {\n container.modem.demuxStream(stream, outStream('updater'), errStream('updater'));\n\n stream.on('end', () => {\n resolve();\n });\n\n stream.on('error', (error) => {\n reject(error);\n });\n });\n\n // Wait a bit for the exec to complete properly\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n const inspection = await exec.inspect();\n if (inspection.ExitCode !== 0) {\n throw new Error(`Command failed with exit code ${inspection.ExitCode}: ${cmd.join(' ')}`);\n }\n },\n};\n","import { Readable } from 'node:stream';\nimport { logger } from '@paklo/core/logger';\nimport Docker from 'dockerode';\n\nconst MAX_RETRIES = 5; // Maximum number of retries\nconst INITIAL_DELAY_MS = 5000; // Initial delay in milliseconds for backoff\n\n// Code below is borrowed and adapted from dependabot-action\n\nconst sleep = async (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst endOfStream = async (docker: Docker, stream: Readable): Promise<void> => {\n return new Promise((resolve, reject) => {\n docker.modem.followProgress(stream, (err: Error | null) => (err ? reject(err) : resolve(undefined)));\n });\n};\n\nexport function getOrgFromImage(imageName: string): string {\n const parts = imageName.split('/');\n if (parts.length >= 3 && parts[0] === 'ghcr.io') {\n return parts[1]!; // The domain is always the second part\n }\n return 'unknown'; // Fallback case if structure is unexpected\n}\n\nexport type MetricReporter = (\n metricName: string,\n metricType: 'increment' | 'gauge',\n value: number,\n additionalTags?: Record<string, string>,\n) => Promise<void>;\n\n/** Fetch the configured updater image, if it isn't already available. */\nexport const ImageService = {\n async pull(imageName: string, sendMetric?: MetricReporter, force = false): Promise<void> {\n /*\n This method fetches images hosts on GitHub infrastructure.\n\n We expose the `fetch_image` utility method to allow us to pull in arbitrary images for unit tests.\n */\n if (!(imageName.startsWith('ghcr.io/') || imageName.startsWith('docker.pkg.github.com/'))) {\n throw new Error('Only images distributed via docker.pkg.github.com or ghcr.io can be fetched');\n }\n\n const docker = new Docker();\n const org = getOrgFromImage(imageName);\n try {\n const image = await docker.getImage(imageName).inspect();\n if (!force) {\n logger.info(`Resolved ${imageName} to existing ${image.RepoDigests}`);\n return;\n } // else fallthrough to pull\n } catch (e: unknown) {\n if (e instanceof Error && !e.message.includes('no such image')) {\n throw e;\n } // else fallthrough to pull\n }\n\n const auth = {}; // Images are public so not authentication info is required\n await this.fetchImageWithRetry(imageName, auth, docker, sendMetric, org);\n },\n\n /* Retrieve the image using the auth details provided, if any with retry and backoff */\n async fetchImageWithRetry(\n imageName: string,\n auth = {},\n docker = new Docker(),\n sendMetric: MetricReporter | undefined,\n org: string,\n ): Promise<void> {\n let attempt = 0;\n\n while (attempt < MAX_RETRIES) {\n try {\n logger.info(`Pulling image ${imageName} (attempt ${attempt + 1})...`);\n /* To avoid sending metrics during unit tests (fetch_image) */\n if (sendMetric) {\n await sendMetric('ghcr_image_pull', 'increment', 1, {\n org,\n });\n }\n const stream = await docker.pull(imageName, { authconfig: auth });\n await endOfStream(docker, new Readable().wrap(stream));\n logger.info(`Pulled image ${imageName}`);\n return; // Exit on success\n } catch (error) {\n if (!(error instanceof Error)) throw error; // Ensure error is an instance of Error\n\n // Handle 429 Too Many Requests separately\n if (\n error.message.includes('429 Too Many Requests') ||\n error.message.toLowerCase().includes('too many requests')\n ) {\n attempt++; // Only increment attempt on 429\n if (attempt >= MAX_RETRIES) {\n logger.error(`Failed to pull image ${imageName} after ${MAX_RETRIES} attempts.`);\n throw error;\n }\n\n // Add jitter to avoid synchronization issues\n // biome-ignore lint/style/useExponentiationOperator: This is clearer for now\n const baseDelay = INITIAL_DELAY_MS * Math.pow(2, attempt);\n const jitter = Math.random() * baseDelay;\n const delay = baseDelay / 2 + jitter;\n\n logger.warn(`Received Too Many Requests error. Retrying in ${(delay / 1000).toFixed(2)} seconds...`);\n await sleep(delay);\n } else {\n // Non-429 errors should NOT be retried\n logger.error(`Fatal error pulling image ${imageName}: ${error.message}`);\n throw error; // Exit immediately\n }\n }\n }\n },\n};\n","// Code below is borrowed and adapted from dependabot-action\n\n/*\n `jobId` is intentionally a string even though we copied from code that used number\n We generate the job identifiers using Snowflake which produces bigint\n and bigint cannot be serialized to JSON, so we use string everywhere instead.\n The hosted dependabot possible uses auto-incrementing numbers for jobIds in their database,\n but not all databases support this.\n*/\n\nexport class JobParameters {\n constructor(\n readonly jobId: string,\n readonly jobToken: string,\n readonly credentialsToken: string,\n readonly dependabotApiUrl: string,\n readonly dependabotApiDockerUrl: string,\n readonly updaterImage: string,\n ) {}\n}\n\nexport function getJobParameters(input: {\n jobId?: string;\n jobToken?: string;\n credentialsToken?: string;\n dependabotApiUrl?: string;\n dependabotApiDockerUrl?: string;\n updaterImage?: string;\n}): JobParameters | null {\n return new JobParameters(\n input.jobId as string,\n input.jobToken as string,\n input.credentialsToken as string,\n input.dependabotApiUrl as string,\n input.dependabotApiDockerUrl as string,\n input.updaterImage as string,\n );\n}\n","import { readFile } from 'node:fs/promises';\nimport type { CertificateAuthority, DependabotCredential, DependabotProxyConfig } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type Docker from 'dockerode';\nimport type { Container, Network } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport { errStream, nullStream, outStream } from './utils';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport type Proxy = {\n container: Container;\n network: Network;\n networkName: string;\n url: () => Promise<string>;\n cert: string;\n shutdown: () => Promise<void>;\n};\n\nconst KEY_SIZE = 2048;\nconst KEY_EXPIRY_YEARS = 2;\nconst CONFIG_FILE_PATH = '/';\nexport const CONFIG_FILE_NAME = 'config.json';\nconst CA_CERT_INPUT_PATH = '/usr/local/share/ca-certificates';\nconst CUSTOM_CA_CERT_NAME = 'custom-ca-cert.crt';\nconst CERT_SUBJECT = [\n { name: 'commonName', value: 'Dependabot Internal CA' },\n { name: 'organizationName', value: 'GitHub Inc.' },\n { shortName: 'OU', value: 'Dependabot' },\n { name: 'countryName', value: 'US' },\n { shortName: 'ST', value: 'California' },\n { name: 'localityName', value: 'San Francisco' },\n];\n\nexport class ProxyBuilder {\n constructor(\n private readonly docker: Docker,\n private readonly proxyImage: string,\n private readonly cachedMode: boolean,\n private readonly debug: boolean,\n ) {}\n\n async run(\n jobId: string,\n jobToken: string,\n dependabotApiUrl: string,\n credentials: DependabotCredential[],\n ): Promise<Proxy> {\n const name = `dependabot-job-${jobId}-proxy`;\n const config = await this.buildProxyConfig(credentials);\n const cert = config.ca.cert;\n\n const externalNetworkName = `dependabot-job-${jobId}-external-network`;\n const externalNetwork = await this.ensureNetwork(externalNetworkName, false);\n\n const internalNetworkName = `dependabot-job-${jobId}-internal-network`;\n const internalNetwork = await this.ensureNetwork(internalNetworkName, true);\n\n const container = await this.createContainer(\n jobId,\n jobToken,\n dependabotApiUrl,\n name,\n externalNetwork,\n internalNetwork,\n internalNetworkName,\n );\n\n await ContainerService.storeInput(CONFIG_FILE_NAME, CONFIG_FILE_PATH, container, config);\n\n const customCAPath = this.customCAPath();\n if (customCAPath) {\n logger.info('Detected custom CA certificate, adding to proxy');\n\n const customCert = (await readFile(customCAPath, 'utf8')).toString();\n await ContainerService.storeCert(CUSTOM_CA_CERT_NAME, CA_CERT_INPUT_PATH, container, customCert);\n }\n\n const stream = await container.attach({\n stream: true,\n stdout: true,\n stderr: true,\n });\n container.modem.demuxStream(\n stream,\n // proxy generates lots of logs that we do not need unless debugging\n // this should save on disk space in agents running Azure pipelines\n this.debug ? outStream(' proxy') : nullStream,\n this.debug ? errStream(' proxy') : nullStream,\n );\n\n const url = async (): Promise<string> => {\n const containerInfo = await container.inspect();\n\n if (containerInfo.State.Running === true) {\n const ipAddress = containerInfo.NetworkSettings.Networks[`${internalNetworkName}`]!.IPAddress;\n return `http://${ipAddress}:1080`;\n } else {\n throw new Error(\"proxy container isn't running\");\n }\n };\n\n return {\n container,\n network: internalNetwork,\n networkName: internalNetworkName,\n url,\n cert,\n shutdown: async () => {\n await container.stop();\n await container.remove();\n await Promise.all([externalNetwork.remove(), internalNetwork.remove()]);\n },\n };\n }\n\n private async ensureNetwork(name: string, internal = true): Promise<Network> {\n const networks = await this.docker.listNetworks({\n filters: JSON.stringify({ name: [name] }),\n });\n if (networks.length > 0) {\n return this.docker.getNetwork(networks[0]!.Id);\n } else {\n return await this.docker.createNetwork({ Name: name, Internal: internal });\n }\n }\n\n private async buildProxyConfig(credentials: DependabotCredential[]): Promise<DependabotProxyConfig> {\n const ca = await ProxyBuilder.generateCertificateAuthority();\n\n const config: DependabotProxyConfig = { all_credentials: credentials, ca };\n\n return config;\n }\n\n public static async generateCertificateAuthority(): Promise<CertificateAuthority> {\n // node-forge is a CommonJS module, so we need to import it dynamically\n const {\n default: { md, pki },\n } = await import('node-forge');\n const keys = pki.rsa.generateKeyPair(KEY_SIZE);\n const cert = pki.createCertificate();\n\n cert.publicKey = keys.publicKey;\n cert.serialNumber = '01';\n cert.validity.notBefore = new Date();\n cert.validity.notAfter = new Date();\n cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + KEY_EXPIRY_YEARS);\n\n cert.setSubject(CERT_SUBJECT);\n cert.setIssuer(CERT_SUBJECT);\n\n cert.setExtensions([\n {\n name: 'basicConstraints',\n cA: true,\n critical: true,\n },\n {\n name: 'keyUsage',\n digitalSignature: true,\n keyEncipherment: true,\n keyCertSign: true,\n cRLSign: true,\n critical: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n },\n {\n name: 'subjectKeyIdentifier',\n },\n {\n name: 'authorityKeyIdentifier',\n keyIdentifier: true,\n authorityCertIssuer: true,\n authorityCertSerialNumber: cert.serialNumber,\n },\n ]);\n\n cert.sign(keys.privateKey, md.sha256.create());\n\n const pem = pki.certificateToPem(cert);\n const key = pki.privateKeyToPem(keys.privateKey);\n return { cert: pem, key };\n }\n\n private async createContainer(\n jobId: string,\n jobToken: string,\n dependabotApiUrl: string,\n containerName: string,\n externalNetwork: Network,\n internalNetwork: Network,\n internalNetworkName: string,\n ): Promise<Container> {\n const container = await this.docker.createContainer({\n Image: this.proxyImage,\n name: containerName,\n AttachStdout: true,\n AttachStderr: true,\n Env: [\n `http_proxy=${process.env.http_proxy || process.env.HTTP_PROXY || ''}`,\n `https_proxy=${process.env.https_proxy || process.env.HTTPS_PROXY || ''}`,\n `no_proxy=${process.env.no_proxy || process.env.NO_PROXY || ''}`,\n `JOB_ID=${jobId}`,\n `JOB_TOKEN=${jobToken}`,\n `PROXY_CACHE=${this.cachedMode ? 'true' : 'false'}`,\n `DEPENDABOT_API_URL=${dependabotApiUrl}`,\n `ACTIONS_ID_TOKEN_REQUEST_TOKEN=${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN || ''}`,\n `ACTIONS_ID_TOKEN_REQUEST_URL=${process.env.ACTIONS_ID_TOKEN_REQUEST_URL || ''}`,\n ],\n Entrypoint: ['sh', '-c', '/usr/sbin/update-ca-certificates && /update-job-proxy'],\n\n HostConfig: {\n NetworkMode: internalNetworkName,\n ExtraHosts: ['host.docker.internal:host-gateway'], // needed for Docker on Linux\n },\n });\n\n await externalNetwork.connect({ Container: container.id });\n\n logger.info(`Created proxy container: ${container.id}`);\n return container;\n }\n\n private customCAPath(): string | undefined {\n if ('CUSTOM_CA_PATH' in process.env) {\n return process.env.CUSTOM_CA_PATH;\n }\n // default to node.js configuration\n return process.env.NODE_EXTRA_CA_CERTS;\n }\n}\n","","// biome-ignore-all lint/suspicious/noShadowRestrictedNames: Proxy is okay\n\nimport type { FileFetcherInput, FileUpdaterInput } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type Docker from 'dockerode';\nimport type { Container } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport type { JobParameters } from './params';\nimport type { Proxy } from './proxy';\nimport { extractUpdaterSha } from './utils';\n\nexport const JOB_INPUT_FILENAME = 'job.json';\nexport const JOB_INPUT_PATH = `/home/dependabot/dependabot-updater`;\nexport const REPO_CONTENTS_PATH = '/home/dependabot/dependabot-updater/repo';\nexport const CA_CERT_INPUT_PATH = '/usr/local/share/ca-certificates';\nexport const CA_CERT_FILENAME = 'dbot-ca.crt';\nconst UPDATER_MAX_MEMORY = 8 * 1024 * 1024 * 1024; // 8GB in bytes\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class UpdaterBuilder {\n constructor(\n private readonly docker: Docker,\n private readonly jobParams: JobParameters,\n private readonly input: FileFetcherInput | FileUpdaterInput,\n private readonly proxy: Proxy,\n\n private readonly updaterImage: string,\n ) {}\n\n async run(containerName: string): Promise<Container> {\n const proxyUrl = await this.proxy.url();\n const updaterSha = extractUpdaterSha(this.updaterImage);\n\n const envVars = [\n `GITHUB_ACTIONS=${process.env.GITHUB_ACTIONS}`,\n `DEPENDABOT_JOB_ID=${this.jobParams.jobId}`,\n `DEPENDABOT_JOB_TOKEN=`,\n `DEPENDABOT_JOB_PATH=${JOB_INPUT_PATH}/${JOB_INPUT_FILENAME}`,\n `DEPENDABOT_OPEN_TIMEOUT_IN_SECONDS=15`,\n `DEPENDABOT_REPO_CONTENTS_PATH=${REPO_CONTENTS_PATH}`,\n `DEPENDABOT_API_URL=${this.jobParams.dependabotApiDockerUrl}`,\n `SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt`,\n `http_proxy=${proxyUrl}`,\n `HTTP_PROXY=${proxyUrl}`,\n `https_proxy=${proxyUrl}`,\n `HTTPS_PROXY=${proxyUrl}`,\n `ENABLE_CONNECTIVITY_CHECK=${process.env.DEPENDABOT_ENABLE_CONNECTIVITY_CHECK || '1'}`,\n\n // for updates relying on .NET (e.g. NuGet) and running on macOS (e.g. dev laptop or local MacMini),\n // we need to disable WriteXorExecute to avoid issues with emulation of Linux containers on macOS hosts\n // with Apple Silicon (M1/M2) chips\n // See - https://github.com/dotnet/runtime/issues/103063#issuecomment-2149599940\n // - https://github.com/dependabot/dependabot-core/issues/5037\n ...(process.platform === 'darwin' ? [`DOTNET_EnableWriteXorExecute=0`] : []),\n ];\n\n // Add DEPENDABOT_UPDATER_SHA if we successfully extracted a SHA\n if (updaterSha !== null) {\n envVars.push(`DEPENDABOT_UPDATER_SHA=${updaterSha}`);\n }\n\n const container = await this.docker.createContainer({\n Image: this.updaterImage,\n name: containerName,\n AttachStdout: true,\n AttachStderr: true,\n User: 'dependabot',\n Env: envVars,\n Cmd: ['/bin/sh'],\n Tty: true,\n HostConfig: {\n Memory: UPDATER_MAX_MEMORY,\n NetworkMode: this.proxy.networkName,\n },\n });\n\n await ContainerService.storeCert(CA_CERT_FILENAME, CA_CERT_INPUT_PATH, container, this.proxy.cert);\n\n await ContainerService.storeInput(JOB_INPUT_FILENAME, JOB_INPUT_PATH, container, this.input);\n\n logger.info(`Created container: ${container.id}`);\n return container;\n }\n}\n","// biome-ignore-all lint/suspicious/noShadowRestrictedNames: Proxy is okay\n\nimport type {\n DependabotCredential,\n DependabotJobConfig,\n FileFetcherInput,\n FileUpdaterInput,\n} from '@paklo/core/dependabot';\nimport Docker, { type Container } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport type { JobParameters } from './params';\nimport { type Proxy, ProxyBuilder } from './proxy';\nimport { UpdaterBuilder } from './updater-builder';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class Updater {\n docker: Docker;\n\n constructor(\n private readonly updaterImage: string,\n private readonly proxyImage: string,\n private readonly params: JobParameters,\n private readonly job: DependabotJobConfig,\n private readonly credentials: DependabotCredential[],\n private readonly debug: boolean,\n ) {\n this.docker = new Docker();\n this.job['credentials-metadata'] = this.generateCredentialsMetadata();\n }\n\n /**\n * Execute an update job and report the result to Dependabot API.\n */\n async runUpdater(): Promise<boolean> {\n const cachedMode = Object.hasOwn(this.job.experiments, 'proxy-cached') === true;\n\n const proxyBuilder = new ProxyBuilder(this.docker, this.proxyImage, cachedMode, this.debug);\n\n const proxy = await proxyBuilder.run(\n this.params.jobId,\n this.params.jobToken,\n this.params.dependabotApiUrl,\n this.credentials,\n );\n await proxy.container.start();\n\n try {\n await this.runUpdate(proxy);\n return true;\n } finally {\n await this.cleanup(proxy);\n }\n }\n\n private generateCredentialsMetadata(): DependabotCredential[] {\n const unique: Set<string> = new Set();\n const result: DependabotCredential[] = [];\n for (const credential of this.credentials) {\n if (credential.type === 'jit_access') {\n continue;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: necessary\n const obj: any = { type: credential.type };\n if (credential.host !== undefined) {\n obj.host = credential.host;\n }\n if (credential.registry !== undefined) {\n obj.registry = credential.registry;\n }\n if (credential.url !== undefined) {\n obj.url = credential.url;\n }\n this.setRegistryFromUrl(obj, credential);\n if (credential['index-url'] !== undefined) {\n obj['index-url'] = credential['index-url'];\n }\n this.setIndexUrlFromUrl(obj, credential);\n if (credential['env-key'] !== undefined) {\n obj['env-key'] = credential['env-key'];\n }\n if (credential.organization !== undefined) {\n obj.organization = credential.organization;\n }\n if (credential['replaces-base'] !== undefined) {\n obj['replaces-base'] = credential['replaces-base'];\n }\n if (credential['public-key-fingerprint'] !== undefined) {\n obj['public-key-fingerprint'] = credential['public-key-fingerprint'];\n }\n if (credential.repo !== undefined) {\n obj.repo = credential.repo;\n }\n const key = JSON.stringify(obj);\n if (!unique.has(key)) {\n unique.add(key);\n result.push(obj as DependabotCredential);\n }\n }\n return result;\n }\n\n private setRegistryFromUrl(obj: DependabotCredential, credential: DependabotCredential): void {\n const typesThatUseRegistryAsHost = ['npm_registry', 'composer_repository', 'docker_registry'];\n\n if (!typesThatUseRegistryAsHost.includes(credential.type)) {\n return;\n }\n\n if (!credential.registry && credential.url) {\n try {\n const parsedURL = new URL(credential.url);\n obj.registry = parsedURL.hostname;\n if (credential.type === 'npm_registry') {\n obj.registry += parsedURL.pathname;\n }\n } catch {\n // If the URL is invalid, we skip setting the registry\n // as it will fall back to the default registry for the given type (e.g., npm, Docker, or Composer).\n }\n }\n }\n\n private setIndexUrlFromUrl(obj: DependabotCredential, credential: DependabotCredential): void {\n if (credential.type !== 'python_index') {\n return;\n }\n if (credential['index-url']) {\n return;\n }\n if (credential.url) {\n try {\n obj['index-url'] = credential.url;\n } catch {\n // If the URL is invalid, we skip setting the index-url\n // as it will fall back to the default index URL for pip.\n }\n }\n }\n\n private async runUpdate(proxy: Proxy): Promise<void> {\n const name = `dependabot-job-${this.params.jobId}`;\n const container = await this.createContainer(proxy, name, {\n job: this.job,\n });\n\n await ContainerService.run(container, this.job.command);\n }\n\n private async createContainer(\n proxy: Proxy,\n containerName: string,\n input: FileFetcherInput | FileUpdaterInput,\n ): Promise<Container> {\n const builder = new UpdaterBuilder(this.docker, this.params, input, proxy, this.updaterImage);\n return builder.run(containerName);\n }\n\n private async cleanup(proxy: Proxy): Promise<void> {\n await proxy.shutdown();\n }\n}\n","import crypto from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport os from 'node:os';\nimport { logger } from '@paklo/core/logger';\nimport type { UsageTelemetryRequestData } from '@paklo/core/usage';\nimport ky from 'ky';\nimport { z } from 'zod';\n\nimport packageJson from '../package.json';\nimport { ApiClient, CredentialFetchingError, type SecretMasker } from './api-client';\nimport { PROXY_IMAGE_NAME, updaterImageName } from './docker-tags';\nimport { ImageService, type MetricReporter } from './image-service';\nimport { getJobParameters } from './params';\nimport { Updater } from './updater';\n\nexport class JobRunnerImagingError extends Error {}\nexport class JobRunnerUpdaterError extends Error {}\n\nexport type RunJobOptions = {\n dependabotApiUrl: string;\n dependabotApiDockerUrl?: string;\n jobId: string;\n jobToken: string;\n credentialsToken: string;\n updaterImage?: string;\n secretMasker: SecretMasker;\n debug: boolean;\n usage: Pick<UsageTelemetryRequestData, 'trigger' | 'provider' | 'owner' | 'project' | 'package-manager'>;\n};\nexport type RunJobResult = { success: true; message?: string } | { success: false; message: string };\n\nexport async function runJob(options: RunJobOptions): Promise<RunJobResult> {\n const { jobId, dependabotApiUrl, dependabotApiDockerUrl, jobToken, credentialsToken, secretMasker, debug, usage } =\n options;\n\n const started = new Date();\n let success = false;\n let message: string | undefined;\n try {\n const params = getJobParameters({\n jobId,\n jobToken,\n credentialsToken,\n dependabotApiUrl,\n dependabotApiDockerUrl: dependabotApiDockerUrl ?? dependabotApiUrl,\n updaterImage: options.updaterImage,\n })!;\n\n const client = ky.create({ headers: { 'User-Agent': `paklo-runner/${packageJson.version}` } });\n const apiClient = new ApiClient(client, params, jobToken, credentialsToken, secretMasker);\n\n // If we fail to succeed in fetching the job details, we cannot be sure the job has entered a 'processing' state,\n // so we do not try attempt to report back an exception if this fails and instead rely on the workflow run\n // webhook as it anticipates scenarios where jobs have failed while 'enqueued'.\n const job = await apiClient.getJobDetails();\n\n // The params can specify which updater image to use. If it doesn't, fall back to the pinned version.\n const updaterImage = params.updaterImage || updaterImageName(job['package-manager']);\n\n // The sendMetrics function is used to send metrics to the API client.\n // It uses the package manager as a tag to identify the metric.\n const sendMetricsWithPackageManager: MetricReporter = async (name, metricType, value, additionalTags = {}) => {\n try {\n await apiClient.sendMetrics(name, metricType, value, {\n package_manager: job['package-manager'],\n ...additionalTags,\n });\n } catch (error) {\n logger.warn(`Metric sending failed for ${name}: ${(error as Error).message}`);\n }\n };\n\n const credentials = (await apiClient.getCredentials()) || [];\n\n const updater = new Updater(updaterImage, PROXY_IMAGE_NAME, params, job, credentials, debug);\n\n try {\n // Using sendMetricsWithPackageManager wrapper to inject package manager tag to\n // avoid passing additional parameters to ImageService.pull method\n await ImageService.pull(updaterImage, sendMetricsWithPackageManager);\n await ImageService.pull(PROXY_IMAGE_NAME, sendMetricsWithPackageManager);\n } catch (err: unknown) {\n if (err instanceof Error) {\n throw new JobRunnerImagingError(err.message);\n }\n }\n\n try {\n await updater.runUpdater();\n } catch (err: unknown) {\n if (err instanceof Error) {\n throw new JobRunnerUpdaterError(err.message);\n }\n }\n success = true;\n } catch (err) {\n if (err instanceof JobRunnerImagingError) {\n message = `Error fetching updater images: ${err.message}`;\n } else if (err instanceof JobRunnerUpdaterError) {\n message = `Error running updater: ${err.message}`;\n } else if (err instanceof CredentialFetchingError) {\n message = `Dependabot was unable to retrieve job credentials: ${err.message}`;\n } else {\n message = `Unknown error: ${(err as Error).message}`;\n }\n }\n\n // send usage telemetry, unless explicitly disabled\n const telemetryDisabled = z.stringbool().optional().parse(process.env.PAKLO_TELEMETRY_DISABLED);\n if (!telemetryDisabled) {\n // detect if we are running inside a Docker container\n const inDocker = await isRunningInDocker();\n const duration = Date.now() - started.getTime();\n const data: UsageTelemetryRequestData = {\n ...usage,\n host: {\n platform: os.platform(),\n release: os.release(),\n arch: os.arch(),\n 'machine-hash': crypto.createHash('sha256').update(os.hostname()).digest('hex'),\n 'docker-container': inDocker,\n },\n version: packageJson.version,\n id: jobId,\n started,\n duration,\n success,\n // error message but truncate to first 1000 characters to avoid sending too much data\n error: message ? { message: message.substring(0, 1000) } : undefined,\n };\n try {\n const json = JSON.stringify(data);\n logger.debug(`Usage telemetry data: ${json}`);\n const resp = await ky.post('https://www.paklo.app/api/usage-telemetry', {\n headers: { 'Content-Type': 'application/json' },\n body: json,\n });\n if (!resp.ok) {\n logger.debug(`Failed to send usage telemetry data: ${resp.status} ${resp.statusText}`);\n }\n } catch (err) {\n logger.debug(`Failed to send usage telemetry data: ${(err as Error).message}`);\n // ignore\n }\n } else {\n logger.debug('Telemetry disabled, not sending usage telemetry data');\n }\n\n logger.info(`Update job ${jobId} completed`);\n return { success, message: message! };\n}\n\n/**\n * Detects if the current process is running inside a Docker container.\n */\nexport async function isRunningInDocker(): Promise<boolean> {\n // Check for .dockerenv file\n if (existsSync('/.dockerenv')) return true;\n\n // Check cgroup\n try {\n const cgroup = await readFile('/proc/self/cgroup', 'utf8');\n return cgroup.includes('docker') || cgroup.includes('kubepods');\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as SecretMasker } from "./api-client-
|
|
2
|
-
import { CreateApiServerAppOptions, DependabotConfig, DependabotCredential, DependabotExperiments, DependabotJobConfig, DependabotRequest, DependabotTokenType, DependabotUpdate, GitAuthor } from "@paklo/core/dependabot";
|
|
1
|
+
import { i as SecretMasker } from "./api-client-DZQQArbU.mjs";
|
|
2
|
+
import { CreateApiServerAppOptions, DependabotCommand, DependabotConfig, DependabotCredential, DependabotExistingGroupPr, DependabotExistingPr, DependabotExperiments, DependabotJobConfig, DependabotRequest, DependabotTokenType, DependabotUpdate, GitAuthor } from "@paklo/core/dependabot";
|
|
3
3
|
|
|
4
4
|
//#region src/local/runner.d.ts
|
|
5
5
|
type RunJobsResult = {
|
|
@@ -14,9 +14,9 @@ type LocalJobsRunnerOptions = {
|
|
|
14
14
|
secretMasker: SecretMasker;
|
|
15
15
|
config: DependabotConfig;
|
|
16
16
|
targetUpdateIds?: number[];
|
|
17
|
+
command: DependabotCommand;
|
|
17
18
|
experiments: DependabotExperiments;
|
|
18
19
|
updaterImage?: string;
|
|
19
|
-
command?: DependabotJobConfig['command'];
|
|
20
20
|
};
|
|
21
21
|
declare abstract class LocalJobsRunner {
|
|
22
22
|
private readonly opt;
|
|
@@ -30,21 +30,15 @@ declare abstract class LocalJobsRunner {
|
|
|
30
30
|
//#endregion
|
|
31
31
|
//#region src/local/server.d.ts
|
|
32
32
|
type LocalDependabotServerAddOptions = {
|
|
33
|
-
/** The ID of the dependabot job. */
|
|
34
|
-
|
|
35
|
-
/** The
|
|
36
|
-
|
|
37
|
-
/** The
|
|
38
|
-
job: DependabotJobConfig;
|
|
39
|
-
/** The authentication token for the job. */
|
|
40
|
-
jobToken: string;
|
|
41
|
-
/** The authentication token for the job. */
|
|
42
|
-
credentialsToken: string;
|
|
43
|
-
/** The credentials associated with the job. */
|
|
33
|
+
/** The ID of the dependabot job. */id: string; /** The dependabot update associated with the job. */
|
|
34
|
+
update: DependabotUpdate; /** The dependabot job configuration. */
|
|
35
|
+
job: DependabotJobConfig; /** The authentication token for the job. */
|
|
36
|
+
jobToken: string; /** The authentication token for the job. */
|
|
37
|
+
credentialsToken: string; /** The credentials associated with the job. */
|
|
44
38
|
credentials: DependabotCredential[];
|
|
45
39
|
};
|
|
46
40
|
type AffectedPullRequestIds = {
|
|
47
|
-
created:
|
|
41
|
+
created: (DependabotExistingPr | DependabotExistingGroupPr)[];
|
|
48
42
|
updated: number[];
|
|
49
43
|
closed: number[];
|
|
50
44
|
};
|
|
@@ -79,12 +73,16 @@ declare abstract class LocalDependabotServer {
|
|
|
79
73
|
debug: boolean | null;
|
|
80
74
|
dependencies: string[] | null;
|
|
81
75
|
'existing-pull-requests': {
|
|
82
|
-
'
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
'pr-number': number;
|
|
77
|
+
dependencies: {
|
|
78
|
+
'dependency-name': string;
|
|
79
|
+
'dependency-version'?: string | null | undefined;
|
|
80
|
+
directory?: string | null | undefined;
|
|
81
|
+
removed?: boolean | null | undefined;
|
|
82
|
+
}[];
|
|
83
|
+
}[];
|
|
87
84
|
'existing-group-pull-requests': {
|
|
85
|
+
'pr-number': number;
|
|
88
86
|
'dependency-group-name': string;
|
|
89
87
|
dependencies: {
|
|
90
88
|
'dependency-name': string;
|
|
@@ -129,7 +127,7 @@ declare abstract class LocalDependabotServer {
|
|
|
129
127
|
'prefix-development'?: string | null | undefined;
|
|
130
128
|
'include-scope'?: boolean | null | undefined;
|
|
131
129
|
};
|
|
132
|
-
command?: "version" | "
|
|
130
|
+
command?: "version" | "update" | "recreate" | "graph" | undefined;
|
|
133
131
|
'dependency-groups'?: {
|
|
134
132
|
name: string;
|
|
135
133
|
rules: {
|
|
@@ -227,4 +225,4 @@ declare abstract class LocalDependabotServer {
|
|
|
227
225
|
}
|
|
228
226
|
//#endregion
|
|
229
227
|
export { LocalJobsRunner as a, LocalDependabotServerOptions as i, LocalDependabotServer as n, LocalJobsRunnerOptions as o, LocalDependabotServerAddOptions as r, RunJobsResult as s, AffectedPullRequestIds as t };
|
|
230
|
-
//# sourceMappingURL=server-
|
|
228
|
+
//# sourceMappingURL=server-B6aYEkTC.d.mts.map
|
|
@@ -150,7 +150,7 @@ var LocalDependabotServer = class {
|
|
|
150
150
|
const affected = this.affectedPrs(id);
|
|
151
151
|
if (!affected) return [];
|
|
152
152
|
return [
|
|
153
|
-
...affected.created,
|
|
153
|
+
...affected.created.map((pr) => pr["pr-number"]),
|
|
154
154
|
...affected.updated,
|
|
155
155
|
...affected.closed
|
|
156
156
|
];
|
|
@@ -201,4 +201,4 @@ var LocalDependabotServer = class {
|
|
|
201
201
|
|
|
202
202
|
//#endregion
|
|
203
203
|
export { LocalJobsRunner as n, LocalDependabotServer as t };
|
|
204
|
-
//# sourceMappingURL=server-
|
|
204
|
+
//# sourceMappingURL=server-BkN82tIp.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-BkN82tIp.mjs","names":[],"sources":["../src/local/runner.ts","../src/local/server.ts"],"sourcesContent":["import type { DependabotCommand, DependabotConfig, DependabotExperiments } from '@paklo/core/dependabot';\nimport { Keygen } from '@paklo/core/keygen';\nimport type { SecretMasker } from '../api-client';\n\nexport type RunJobsResult = { id: string; success: boolean; message?: string; affectedPrs: number[] }[];\n\nexport type LocalJobsRunnerOptions = {\n jobTokenOverride?: string;\n credentialsTokenOverride?: string;\n secretMasker: SecretMasker;\n\n config: DependabotConfig;\n targetUpdateIds?: number[];\n command: DependabotCommand;\n experiments: DependabotExperiments;\n updaterImage?: string;\n};\n\nexport abstract class LocalJobsRunner {\n private readonly opt: LocalJobsRunnerOptions;\n\n constructor(options: LocalJobsRunnerOptions) {\n this.opt = options;\n }\n\n protected makeTokens() {\n const { jobTokenOverride, credentialsTokenOverride } = this.opt;\n return {\n jobToken: jobTokenOverride ?? Keygen.generate(),\n credentialsToken: credentialsTokenOverride ?? Keygen.generate(),\n };\n }\n\n public run(): Promise<RunJobsResult> {\n return Promise.resolve([{ id: '-1', success: false, affectedPrs: [] }]);\n }\n}\n","import type { AddressInfo } from 'node:net';\nimport { createAdaptorServer } from '@hono/node-server';\nimport {\n type CreateApiServerAppOptions,\n createApiServerApp,\n type DependabotCredential,\n type DependabotExistingGroupPr,\n type DependabotExistingPr,\n type DependabotJobConfig,\n type DependabotRequest,\n type DependabotTokenType,\n type DependabotUpdate,\n type GitAuthor,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\n\nexport type LocalDependabotServerAddOptions = {\n /** The ID of the dependabot job. */\n id: string;\n /** The dependabot update associated with the job. */\n update: DependabotUpdate;\n /** The dependabot job configuration. */\n job: DependabotJobConfig;\n /** The authentication token for the job. */\n jobToken: string;\n /** The authentication token for the job. */\n credentialsToken: string;\n /** The credentials associated with the job. */\n credentials: DependabotCredential[];\n};\n\nexport type AffectedPullRequestIds = {\n created: (DependabotExistingPr | DependabotExistingGroupPr)[];\n updated: number[];\n closed: number[];\n};\n\nexport type LocalDependabotServerOptions = Omit<\n CreateApiServerAppOptions,\n 'authenticate' | 'getJob' | 'getCredentials' | 'handle'\n> & {\n author: GitAuthor;\n debug: boolean;\n dryRun: boolean;\n};\nexport abstract class LocalDependabotServer {\n private readonly hostname = 'localhost';\n private readonly server: ReturnType<typeof createAdaptorServer>;\n private readonly trackedJobs = new Map<string, DependabotJobConfig>();\n private readonly updates = new Map<string, DependabotUpdate>();\n private readonly jobTokens = new Map<string, string>();\n private readonly credentialTokens = new Map<string, string>();\n private readonly jobCredentials = new Map<string, DependabotCredential[]>();\n private readonly receivedRequests = new Map<string, DependabotRequest[]>();\n\n protected readonly affectedPullRequestIds = new Map<string, AffectedPullRequestIds>();\n\n constructor(options: LocalDependabotServerOptions) {\n const app = createApiServerApp({\n ...options,\n authenticate: this.authenticate.bind(this),\n getJob: this.job.bind(this),\n getCredentials: this.credentials.bind(this),\n handle: this.handle.bind(this),\n });\n this.server = createAdaptorServer({\n ...app,\n // Workaround for hono not respecting x-forwarded-proto header\n // https://github.com/honojs/node-server/issues/146#issuecomment-3153435672\n fetch: (req) => {\n const url = new URL(req.url);\n url.protocol = req.headers.get('x-forwarded-proto') ?? url.protocol;\n return app.fetch(new Request(url, req));\n },\n });\n }\n\n start(port?: number) {\n // listening to 'localhost' will result to IpV6 only but we need it to be all local\n // interfaces, otherwise containers cannot reach it using host.docker.internal\n this.server.listen(port, '0.0.0.0', () => {\n const info = this.server.address() as AddressInfo;\n logger.info(`API server listening on http://${this.hostname}:${info.port}`);\n });\n }\n\n stop() {\n this.server.close(() => logger.info('API server closed'));\n }\n\n get url() {\n const info = this.server.address() as AddressInfo;\n return `http://${this.hostname}:${info.port}`;\n }\n\n get port() {\n const info = this.server.address() as AddressInfo;\n return info.port;\n }\n\n get jobs() {\n return this.trackedJobs;\n }\n\n /**\n * Adds a dependabot job.\n * @param value - The dependabot job details.\n */\n add(value: LocalDependabotServerAddOptions) {\n const { id, update, job, jobToken, credentialsToken, credentials } = value;\n const {\n trackedJobs,\n updates,\n jobTokens,\n credentialTokens,\n jobCredentials,\n receivedRequests,\n affectedPullRequestIds,\n } = this;\n trackedJobs.set(id, job);\n updates.set(id, update);\n jobTokens.set(id, jobToken);\n credentialTokens.set(id, credentialsToken);\n jobCredentials.set(id, credentials);\n receivedRequests.set(id, []);\n affectedPullRequestIds.set(id, { created: [], updated: [], closed: [] });\n }\n\n /**\n * Gets a dependabot job by ID.\n * @param id - The ID of the dependabot job to get.\n * @returns The dependabot job, or undefined if not found.\n */\n job(id: string): Promise<DependabotJobConfig | undefined> {\n return Promise.resolve(this.trackedJobs.get(id));\n }\n\n /**\n * Gets a dependabot update by ID of the job.\n * @param id - The ID of the dependabot job to get.\n * @returns The dependabot update, or undefined if not found.\n */\n update(id: string): DependabotUpdate | undefined {\n return this.updates.get(id);\n }\n\n /**\n * Gets a token by ID of the job.\n * @param id - The ID of the dependabot job to get.\n * @returns The job token, or undefined if not found.\n */\n token(id: string, type: DependabotTokenType): string | undefined {\n return type === 'job' ? this.jobTokens.get(id) : this.credentialTokens.get(id);\n }\n\n /**\n * Gets the credentials for a dependabot job by ID.\n * @param id - The ID of the dependabot job to get credentials for.\n * @returns The credentials for the job, or undefined if not found.\n */\n credentials(id: string): Promise<DependabotCredential[] | undefined> {\n return Promise.resolve(this.jobCredentials.get(id));\n }\n\n /**\n * Gets the received requests for a dependabot job by ID.\n * @param id - The ID of the dependabot job to get requests for.\n * @returns The received requests for the job, or undefined if not found.\n */\n requests(id: string): DependabotRequest[] | undefined {\n return this.receivedRequests.get(id);\n }\n\n /**\n * Gets the IDs of pull requests affected by a dependabot job by ID.\n * @param id - The ID of the dependabot job to get affected pull request IDs for.\n * @returns The affected pull request IDs for the job, or undefined if not found.\n */\n affectedPrs(id: string): AffectedPullRequestIds | undefined {\n const { affectedPullRequestIds } = this;\n return affectedPullRequestIds.get(id);\n }\n\n /**\n * Gets all IDs of pull requests affected by a dependabot job by ID.\n * @param id - The ID of the dependabot job to get affected pull request IDs for.\n * @returns The affected pull request IDs for the job, or undefined if not found.\n */\n allAffectedPrs(id: string): number[] {\n const affected = this.affectedPrs(id);\n if (!affected) return [];\n return [...affected.created.map((pr) => pr['pr-number']), ...affected.updated, ...affected.closed];\n }\n\n /**\n * Clears all data associated with a dependabot job by ID.\n * This should be called when the job is no longer needed.\n * @param id - The ID of the dependabot job to clear.\n */\n clear(id: string) {\n this.trackedJobs.delete(id);\n this.updates.delete(id);\n this.jobTokens.delete(id);\n this.credentialTokens.delete(id);\n this.jobCredentials.delete(id);\n this.receivedRequests.delete(id);\n this.affectedPullRequestIds.delete(id);\n }\n\n /**\n * Authenticates a dependabot job.\n * @param id - The ID of the dependabot job.\n * @param value - The authentication value (e.g., API key).\n * @returns A promise that resolves to a boolean indicating whether the authentication was successful.\n */\n protected async authenticate(type: DependabotTokenType, id: string, value: string): Promise<boolean> {\n const token = type === 'job' ? this.jobTokens.get(id) : this.credentialTokens.get(id);\n if (!token) {\n logger.debug(`Authentication failed: ${type} token ${id} not found`);\n return false;\n }\n if (token !== value) {\n logger.debug(`Authentication failed: invalid token for ${type} token ${id}`);\n return false;\n }\n return true;\n }\n\n /**\n * Handles a dependabot request.\n * @param id - The ID of the dependabot job.\n * @param request - The dependabot request to handle.\n * @returns A promise that resolves to the result of handling the request.\n */\n protected handle(id: string, request: DependabotRequest): Promise<boolean> {\n this.receivedRequests.get(id)!.push(request);\n return Promise.resolve(true);\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paklo/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "mburumaxwell",
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@hono/node-server": "1.19.9",
|
|
42
42
|
"dockerode": "4.0.9",
|
|
43
|
-
"ky": "1.14.
|
|
43
|
+
"ky": "1.14.3",
|
|
44
44
|
"node-forge": "1.3.3",
|
|
45
45
|
"tar-stream": "3.1.7",
|
|
46
|
-
"zod": "4.3.
|
|
47
|
-
"@paklo/core": "0.
|
|
46
|
+
"zod": "4.3.6",
|
|
47
|
+
"@paklo/core": "0.13.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@types/dockerode": "4.0.1",
|
|
51
|
-
"@types/node": "25.0
|
|
51
|
+
"@types/node": "25.2.0",
|
|
52
52
|
"@types/node-forge": "1.3.14",
|
|
53
53
|
"@types/tar-stream": "3.1.4",
|
|
54
|
-
"tsdown": "0.
|
|
54
|
+
"tsdown": "0.20.3",
|
|
55
55
|
"tsx": "4.21.0"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"dev": "tsdown --watch",
|
|
62
|
-
"
|
|
62
|
+
"typecheck": "tsc",
|
|
63
63
|
"build": "tsdown",
|
|
64
64
|
"lint": "biome check",
|
|
65
65
|
"test": "vitest",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-BsKh8vDS.mjs","names":["dockerContainerConfig.proxy","dockerContainerConfig","stream","stream","docker","CA_CERT_INPUT_PATH","docker","stream","docker","proxy","proxy","packageJson.version"],"sources":["../src/api-client.ts","../docker/containers.json","../src/docker-tags.ts","../src/utils.ts","../src/container-service.ts","../src/image-service.ts","../src/params.ts","../src/proxy.ts","../package.json","../src/updater-builder.ts","../src/updater.ts","../src/run.ts"],"sourcesContent":["import type {\n DependabotCredential,\n DependabotJobConfig,\n DependabotMetric,\n DependabotRecordUpdateJobError,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport { isHTTPError, type KyInstance, type KyResponse } from 'ky';\nimport type { JobParameters } from './params';\n\nexport class JobDetailsFetchingError extends Error {}\nexport class CredentialFetchingError extends Error {}\nexport type SecretMasker = (value: string) => void;\n\nexport class ApiClient {\n private dependabotApiUrl: string;\n private jobToken: string;\n constructor(\n private readonly client: KyInstance,\n readonly params: JobParameters,\n jobToken: string,\n private readonly credentialsToken: string,\n private readonly secretMasker: SecretMasker,\n ) {\n // if dependabotApiUrl contains \"host.docker.internal\", we need to replace it with \"localhost\" for local calls\n const baseUrl = params.dependabotApiUrl.replace('host.docker.internal', 'localhost');\n this.dependabotApiUrl = baseUrl;\n this.jobToken = jobToken;\n }\n\n // We use a static unknown SHA when marking a job as complete from the action\n // to remain in parity with the existing runner.\n UnknownSha = {\n 'base-commit-sha': 'unknown',\n };\n\n // Getter for jobToken\n getJobToken(): string {\n return this.jobToken;\n }\n\n async getJobDetails(): Promise<DependabotJobConfig> {\n const detailsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/details`;\n try {\n const res = await this.getWithRetry<DependabotJobConfig>(detailsURL, this.jobToken);\n if (res.status !== 200) {\n throw new JobDetailsFetchingError(\n `fetching job details: unexpected status code: ${res.status}: ${JSON.stringify(await res.json())}`,\n );\n }\n const data = await res.json();\n if (!data) {\n throw new JobDetailsFetchingError(`fetching job details: missing response`);\n }\n\n return data;\n } catch (error) {\n if (error instanceof JobDetailsFetchingError) {\n throw error;\n } else if (isHTTPError(error)) {\n throw new JobDetailsFetchingError(\n `fetching job details: unexpected status code: ${error.response.status}: ${error.message}`,\n );\n } else if (error instanceof Error) {\n throw new JobDetailsFetchingError(`fetching job details: ${error.name}: ${error.message}`);\n }\n throw error;\n }\n }\n\n async getCredentials(): Promise<DependabotCredential[]> {\n const credentialsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/credentials`;\n try {\n const res = await this.getWithRetry<DependabotCredential[]>(credentialsURL, this.credentialsToken);\n\n if (res.status !== 200) {\n throw new CredentialFetchingError(\n `fetching credentials: unexpected status code: ${res.status}: ${JSON.stringify(await res.json())}`,\n );\n }\n const data = await res.json();\n if (!data) {\n throw new CredentialFetchingError(`fetching credentials: missing response`);\n }\n\n // Mask any secrets we've just retrieved from environment logs\n for (const credential of data) {\n if (credential.password) {\n this.secretMasker(credential.password);\n }\n if (credential.token) {\n this.secretMasker(credential.token);\n }\n if (credential['auth-key']) {\n this.secretMasker(credential['auth-key']);\n }\n }\n\n return data;\n } catch (error: unknown) {\n if (error instanceof CredentialFetchingError) {\n throw error;\n } else if (isHTTPError(error)) {\n throw new CredentialFetchingError(\n `fetching credentials: unexpected status code: ${error.response.status}: ${error.message}`,\n );\n } else if (error instanceof Error) {\n throw new CredentialFetchingError(`fetching credentials: ${error.name}: ${error.message}`);\n }\n throw error;\n }\n }\n\n async reportJobError(error: DependabotRecordUpdateJobError): Promise<void> {\n const recordErrorURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/record_update_job_error`;\n const res = await this.client.post(recordErrorURL, {\n json: error,\n headers: { Authorization: this.jobToken },\n });\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n async markJobAsProcessed(): Promise<void> {\n const markAsProcessedURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/mark_as_processed`;\n const res = await this.client.patch(markAsProcessedURL, {\n json: this.UnknownSha,\n headers: { Authorization: this.jobToken },\n });\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n async sendMetrics(\n name: string,\n metricType: 'increment' | 'gauge',\n value: number,\n additionalTags: Record<string, string> = {},\n ): Promise<void> {\n try {\n await this.reportMetrics([\n {\n metric: `dependabot.action.${name}`,\n type: metricType,\n value,\n tags: additionalTags,\n },\n ]);\n logger.info(`Successfully sent metric (dependabot.action.${name}) to remote API endpoint`);\n } catch (error) {\n // metrics should typically not cause critical path failure so we log the\n // failure and continue with the job\n logger.warn(`Metrics reporting failed: ${(error as Error).message}`);\n }\n }\n\n async reportMetrics(metrics: DependabotMetric[]): Promise<void> {\n const metricsURL = `${this.dependabotApiUrl}/update_jobs/${this.params.jobId}/record_metrics`;\n const res = await this.client.post(metricsURL, {\n json: { data: metrics },\n headers: { Authorization: this.jobToken },\n });\n\n if (res.status !== 204) {\n throw new Error(`Unexpected status code: ${res.status}`);\n }\n }\n\n private async getWithRetry<T>(url: string, token: string, options?: RequestInit): Promise<KyResponse<T>> {\n const execute = async (): Promise<KyResponse<T>> => {\n const res = await this.client.get<T>(url, {\n headers: { Authorization: token },\n retry: {\n limit: 3,\n // other default options are sufficient:\n // https://github.com/sindresorhus/ky#retry\n // delay: attemptCount => 0.3 * (2 ** (attemptCount - 1)) * 1000\n // statusCodes: 408 413 429 500 502 503 504\n // afterStatusCodes: 413, 429, 503\n },\n hooks: {\n beforeRetry: [\n async ({ request, options, error, retryCount }) => {\n if (isHTTPError(error)) {\n logger.warn(`Retrying failed request with status code: ${error.response.status}`);\n }\n },\n ],\n },\n ...options,\n });\n\n return res;\n };\n\n return execute();\n }\n}\n","","import dockerContainerConfig from '../docker/containers.json';\n\nexport const PROXY_IMAGE_NAME = dockerContainerConfig.proxy;\n\nexport function updaterImageName(packageManager: string): string {\n return dockerContainerConfig[packageManager as keyof typeof dockerContainerConfig];\n}\n\nconst updaterRegex = /ghcr.io\\/dependabot\\/dependabot-updater-([\\w+])/;\n\nexport function updaterImages(): string[] {\n return Object.values(dockerContainerConfig).filter((image) => image.match(updaterRegex));\n}\n\nconst imageNamePattern =\n '^(?<repository>(([a-zA-Z0-9._-]+([:[0-9]+[^/]))?([a-zA-Z0-9._/-]+)?))(:[a-zA-Z0-9._/-]+)?(?<digest>@sha256:[a-zA-Z0-9]{64})?$';\n\nexport function repositoryName(imageName: string): string {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n return match.groups.repository!;\n } else {\n throw Error('invalid image name');\n }\n}\n\nexport function hasDigest(imageName: string): boolean {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n if (match?.groups.digest) {\n return true;\n }\n return false;\n } else {\n throw Error('invalid image name');\n }\n}\n\nexport function digestName(imageName: string): string {\n const match = imageName.match(imageNamePattern);\n\n if (match?.groups) {\n return match.groups.repository! + match.groups.digest;\n } else {\n throw Error('invalid image name');\n }\n}\n","import stream, { type Writable } from 'node:stream';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport const nullStream: Writable = new stream.Writable({ write: (__, _, next) => next() });\n\nexport const outStream = (prefix: string): Writable => {\n return new stream.Writable({\n write(chunk, _, next) {\n process.stdout.write(`${prefix} | ${chunk.toString()}`);\n next();\n },\n });\n};\n\nexport const errStream = (prefix: string): Writable => {\n return new stream.Writable({\n write(chunk, _, next) {\n process.stderr.write(`${prefix} | ${chunk.toString()}`);\n next();\n },\n });\n};\n\n/**\n * Extracts the SHA from an updater image string.\n * @param updaterImage - Image string in the format \"image:sha\" or \"registry/image:sha\"\n * @returns The SHA part after the last colon, or null if no colon is found\n */\nexport const extractUpdaterSha = (updaterImage: string): string | null => {\n const match = updaterImage.match(/:([^:]*)$/);\n return match ? match[1]! : null;\n};\n","import type { DependabotProxyConfig, FileFetcherInput, FileUpdaterInput } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type { Container } from 'dockerode';\nimport { pack } from 'tar-stream';\nimport { errStream, outStream } from './utils';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class ContainerRuntimeError extends Error {}\n\nconst RWX_ALL = 0o777;\n\nexport const ContainerService = {\n async storeInput(\n name: string,\n path: string,\n container: Container,\n input: FileFetcherInput | FileUpdaterInput | DependabotProxyConfig,\n ): Promise<void> {\n const tar = pack();\n tar.entry({ name, mode: RWX_ALL }, JSON.stringify(input));\n tar.finalize();\n await container.putArchive(tar, { path });\n },\n\n async storeCert(name: string, path: string, container: Container, cert: string): Promise<void> {\n const tar = pack();\n tar.entry({ name }, cert);\n tar.finalize();\n await container.putArchive(tar, { path });\n },\n\n async run(container: Container, command?: string): Promise<boolean> {\n try {\n // Start the container\n await container.start();\n logger.info(`Started container ${container.id}`);\n\n // Check if this is a dependabot container (has the expected structure)\n const containerInfo = await container.inspect();\n const isDependabotContainer = containerInfo.Config?.Env?.some((env) => env.startsWith('DEPENDABOT_JOB_ID='));\n\n if (isDependabotContainer) {\n // For dependabot containers, run CA certificates update as root first\n await this.execCommand(container, ['/usr/sbin/update-ca-certificates'], 'root');\n\n // Then run the dependabot commands as dependabot user\n const dependabotCommands = [\n 'mkdir -p /home/dependabot/dependabot-updater/output',\n // 'fetch_files' command removed as it is now a no-op\n ];\n\n if (command === 'graph') {\n dependabotCommands.push('$DEPENDABOT_HOME/dependabot-updater/bin/run update_graph');\n } else {\n dependabotCommands.push('$DEPENDABOT_HOME/dependabot-updater/bin/run update_files');\n }\n\n for (const cmd of dependabotCommands) {\n await this.execCommand(container, ['/bin/sh', '-c', cmd], 'dependabot');\n }\n } else {\n // For test containers and other containers, just wait for completion\n const outcome = await container.wait();\n if (outcome.StatusCode !== 0) {\n throw new Error(`Container exited with code ${outcome.StatusCode}`);\n }\n }\n\n return true;\n } catch (error) {\n logger.info(`Failure running container ${container.id}: ${error}`);\n throw new ContainerRuntimeError('The updater encountered one or more errors.');\n } finally {\n try {\n await container.remove({ v: true, force: true });\n logger.info(`Cleaned up container ${container.id}`);\n } catch (error) {\n logger.info(`Failed to clean up container ${container.id}: ${error}`);\n }\n }\n },\n\n async execCommand(container: Container, cmd: string[], user: string): Promise<void> {\n const exec = await container.exec({\n Cmd: cmd,\n User: user,\n AttachStdout: true,\n AttachStderr: true,\n });\n\n const stream = await exec.start({});\n\n // Wait for the stream to end\n await new Promise<void>((resolve, reject) => {\n container.modem.demuxStream(stream, outStream('updater'), errStream('updater'));\n\n stream.on('end', () => {\n resolve();\n });\n\n stream.on('error', (error) => {\n reject(error);\n });\n });\n\n // Wait a bit for the exec to complete properly\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n const inspection = await exec.inspect();\n if (inspection.ExitCode !== 0) {\n throw new Error(`Command failed with exit code ${inspection.ExitCode}: ${cmd.join(' ')}`);\n }\n },\n};\n","import { Readable } from 'node:stream';\nimport { logger } from '@paklo/core/logger';\nimport Docker from 'dockerode';\n\nconst MAX_RETRIES = 5; // Maximum number of retries\nconst INITIAL_DELAY_MS = 5000; // Initial delay in milliseconds for backoff\n\n// Code below is borrowed and adapted from dependabot-action\n\nconst sleep = async (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\nconst endOfStream = async (docker: Docker, stream: Readable): Promise<void> => {\n return new Promise((resolve, reject) => {\n docker.modem.followProgress(stream, (err: Error | null) => (err ? reject(err) : resolve(undefined)));\n });\n};\n\nexport function getOrgFromImage(imageName: string): string {\n const parts = imageName.split('/');\n if (parts.length >= 3 && parts[0] === 'ghcr.io') {\n return parts[1]!; // The domain is always the second part\n }\n return 'unknown'; // Fallback case if structure is unexpected\n}\n\nexport type MetricReporter = (\n metricName: string,\n metricType: 'increment' | 'gauge',\n value: number,\n additionalTags?: Record<string, string>,\n) => Promise<void>;\n\n/** Fetch the configured updater image, if it isn't already available. */\nexport const ImageService = {\n async pull(imageName: string, sendMetric?: MetricReporter, force = false): Promise<void> {\n /*\n This method fetches images hosts on GitHub infrastructure.\n\n We expose the `fetch_image` utility method to allow us to pull in arbitrary images for unit tests.\n */\n if (!(imageName.startsWith('ghcr.io/') || imageName.startsWith('docker.pkg.github.com/'))) {\n throw new Error('Only images distributed via docker.pkg.github.com or ghcr.io can be fetched');\n }\n\n const docker = new Docker();\n const org = getOrgFromImage(imageName);\n try {\n const image = await docker.getImage(imageName).inspect();\n if (!force) {\n logger.info(`Resolved ${imageName} to existing ${image.RepoDigests}`);\n return;\n } // else fallthrough to pull\n } catch (e: unknown) {\n if (e instanceof Error && !e.message.includes('no such image')) {\n throw e;\n } // else fallthrough to pull\n }\n\n const auth = {}; // Images are public so not authentication info is required\n await this.fetchImageWithRetry(imageName, auth, docker, sendMetric, org);\n },\n\n /* Retrieve the image using the auth details provided, if any with retry and backoff */\n async fetchImageWithRetry(\n imageName: string,\n auth = {},\n docker = new Docker(),\n sendMetric: MetricReporter | undefined,\n org: string,\n ): Promise<void> {\n let attempt = 0;\n\n while (attempt < MAX_RETRIES) {\n try {\n logger.info(`Pulling image ${imageName} (attempt ${attempt + 1})...`);\n /* To avoid sending metrics during unit tests (fetch_image) */\n if (sendMetric) {\n await sendMetric('ghcr_image_pull', 'increment', 1, {\n org,\n });\n }\n const stream = await docker.pull(imageName, { authconfig: auth });\n await endOfStream(docker, new Readable().wrap(stream));\n logger.info(`Pulled image ${imageName}`);\n return; // Exit on success\n } catch (error) {\n if (!(error instanceof Error)) throw error; // Ensure error is an instance of Error\n\n // Handle 429 Too Many Requests separately\n if (\n error.message.includes('429 Too Many Requests') ||\n error.message.toLowerCase().includes('too many requests')\n ) {\n attempt++; // Only increment attempt on 429\n if (attempt >= MAX_RETRIES) {\n logger.error(`Failed to pull image ${imageName} after ${MAX_RETRIES} attempts.`);\n throw error;\n }\n\n // Add jitter to avoid synchronization issues\n // biome-ignore lint/style/useExponentiationOperator: This is clearer for now\n const baseDelay = INITIAL_DELAY_MS * Math.pow(2, attempt);\n const jitter = Math.random() * baseDelay;\n const delay = baseDelay / 2 + jitter;\n\n logger.warn(`Received Too Many Requests error. Retrying in ${(delay / 1000).toFixed(2)} seconds...`);\n await sleep(delay);\n } else {\n // Non-429 errors should NOT be retried\n logger.error(`Fatal error pulling image ${imageName}: ${error.message}`);\n throw error; // Exit immediately\n }\n }\n }\n },\n};\n","// Code below is borrowed and adapted from dependabot-action\n\n/*\n `jobId` is intentionally a string even though we copied from code that used number\n We generate the job identifiers using Snowflake which produces bigint\n and bigint cannot be serialized to JSON, so we use string everywhere instead.\n The hosted dependabot possible uses auto-incrementing numbers for jobIds in their database,\n but not all databases support this.\n*/\n\nexport class JobParameters {\n constructor(\n readonly jobId: string,\n readonly jobToken: string,\n readonly credentialsToken: string,\n readonly dependabotApiUrl: string,\n readonly dependabotApiDockerUrl: string,\n readonly updaterImage: string,\n ) {}\n}\n\nexport function getJobParameters(input: {\n jobId?: string;\n jobToken?: string;\n credentialsToken?: string;\n dependabotApiUrl?: string;\n dependabotApiDockerUrl?: string;\n updaterImage?: string;\n}): JobParameters | null {\n return new JobParameters(\n input.jobId as string,\n input.jobToken as string,\n input.credentialsToken as string,\n input.dependabotApiUrl as string,\n input.dependabotApiDockerUrl as string,\n input.updaterImage as string,\n );\n}\n","import { readFile } from 'node:fs/promises';\nimport type { CertificateAuthority, DependabotCredential, DependabotProxyConfig } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type Docker from 'dockerode';\nimport type { Container, Network } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport { errStream, nullStream, outStream } from './utils';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport type Proxy = {\n container: Container;\n network: Network;\n networkName: string;\n url: () => Promise<string>;\n cert: string;\n shutdown: () => Promise<void>;\n};\n\nconst KEY_SIZE = 2048;\nconst KEY_EXPIRY_YEARS = 2;\nconst CONFIG_FILE_PATH = '/';\nexport const CONFIG_FILE_NAME = 'config.json';\nconst CA_CERT_INPUT_PATH = '/usr/local/share/ca-certificates';\nconst CUSTOM_CA_CERT_NAME = 'custom-ca-cert.crt';\nconst CERT_SUBJECT = [\n { name: 'commonName', value: 'Dependabot Internal CA' },\n { name: 'organizationName', value: 'GitHub Inc.' },\n { shortName: 'OU', value: 'Dependabot' },\n { name: 'countryName', value: 'US' },\n { shortName: 'ST', value: 'California' },\n { name: 'localityName', value: 'San Francisco' },\n];\n\nexport class ProxyBuilder {\n constructor(\n private readonly docker: Docker,\n private readonly proxyImage: string,\n private readonly cachedMode: boolean,\n private readonly debug: boolean,\n ) {}\n\n async run(\n jobId: string,\n jobToken: string,\n dependabotApiUrl: string,\n credentials: DependabotCredential[],\n ): Promise<Proxy> {\n const name = `dependabot-job-${jobId}-proxy`;\n const config = await this.buildProxyConfig(credentials);\n const cert = config.ca.cert;\n\n const externalNetworkName = `dependabot-job-${jobId}-external-network`;\n const externalNetwork = await this.ensureNetwork(externalNetworkName, false);\n\n const internalNetworkName = `dependabot-job-${jobId}-internal-network`;\n const internalNetwork = await this.ensureNetwork(internalNetworkName, true);\n\n const container = await this.createContainer(\n jobId,\n jobToken,\n dependabotApiUrl,\n name,\n externalNetwork,\n internalNetwork,\n internalNetworkName,\n );\n\n await ContainerService.storeInput(CONFIG_FILE_NAME, CONFIG_FILE_PATH, container, config);\n\n const customCAPath = this.customCAPath();\n if (customCAPath) {\n logger.info('Detected custom CA certificate, adding to proxy');\n\n const customCert = (await readFile(customCAPath, 'utf8')).toString();\n await ContainerService.storeCert(CUSTOM_CA_CERT_NAME, CA_CERT_INPUT_PATH, container, customCert);\n }\n\n const stream = await container.attach({\n stream: true,\n stdout: true,\n stderr: true,\n });\n container.modem.demuxStream(\n stream,\n // proxy generates lots of logs that we do not need unless debugging\n // this should save on disk space in agents running Azure pipelines\n this.debug ? outStream(' proxy') : nullStream,\n this.debug ? errStream(' proxy') : nullStream,\n );\n\n const url = async (): Promise<string> => {\n const containerInfo = await container.inspect();\n\n if (containerInfo.State.Running === true) {\n const ipAddress = containerInfo.NetworkSettings.Networks[`${internalNetworkName}`]!.IPAddress;\n return `http://${ipAddress}:1080`;\n } else {\n throw new Error(\"proxy container isn't running\");\n }\n };\n\n return {\n container,\n network: internalNetwork,\n networkName: internalNetworkName,\n url,\n cert,\n shutdown: async () => {\n await container.stop();\n await container.remove();\n await Promise.all([externalNetwork.remove(), internalNetwork.remove()]);\n },\n };\n }\n\n private async ensureNetwork(name: string, internal = true): Promise<Network> {\n const networks = await this.docker.listNetworks({\n filters: JSON.stringify({ name: [name] }),\n });\n if (networks.length > 0) {\n return this.docker.getNetwork(networks[0]!.Id);\n } else {\n return await this.docker.createNetwork({ Name: name, Internal: internal });\n }\n }\n\n private async buildProxyConfig(credentials: DependabotCredential[]): Promise<DependabotProxyConfig> {\n const ca = await ProxyBuilder.generateCertificateAuthority();\n\n const config: DependabotProxyConfig = { all_credentials: credentials, ca };\n\n return config;\n }\n\n public static async generateCertificateAuthority(): Promise<CertificateAuthority> {\n // node-forge is a CommonJS module, so we need to import it dynamically\n const {\n default: { md, pki },\n } = await import('node-forge');\n const keys = pki.rsa.generateKeyPair(KEY_SIZE);\n const cert = pki.createCertificate();\n\n cert.publicKey = keys.publicKey;\n cert.serialNumber = '01';\n cert.validity.notBefore = new Date();\n cert.validity.notAfter = new Date();\n cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + KEY_EXPIRY_YEARS);\n\n cert.setSubject(CERT_SUBJECT);\n cert.setIssuer(CERT_SUBJECT);\n\n cert.setExtensions([\n {\n name: 'basicConstraints',\n cA: true,\n critical: true,\n },\n {\n name: 'keyUsage',\n digitalSignature: true,\n keyEncipherment: true,\n keyCertSign: true,\n cRLSign: true,\n critical: true,\n },\n {\n name: 'extKeyUsage',\n serverAuth: true,\n clientAuth: true,\n },\n {\n name: 'subjectKeyIdentifier',\n },\n {\n name: 'authorityKeyIdentifier',\n keyIdentifier: true,\n authorityCertIssuer: true,\n authorityCertSerialNumber: cert.serialNumber,\n },\n ]);\n\n cert.sign(keys.privateKey, md.sha256.create());\n\n const pem = pki.certificateToPem(cert);\n const key = pki.privateKeyToPem(keys.privateKey);\n return { cert: pem, key };\n }\n\n private async createContainer(\n jobId: string,\n jobToken: string,\n dependabotApiUrl: string,\n containerName: string,\n externalNetwork: Network,\n internalNetwork: Network,\n internalNetworkName: string,\n ): Promise<Container> {\n const container = await this.docker.createContainer({\n Image: this.proxyImage,\n name: containerName,\n AttachStdout: true,\n AttachStderr: true,\n Env: [\n `http_proxy=${process.env.http_proxy || process.env.HTTP_PROXY || ''}`,\n `https_proxy=${process.env.https_proxy || process.env.HTTPS_PROXY || ''}`,\n `no_proxy=${process.env.no_proxy || process.env.NO_PROXY || ''}`,\n `JOB_ID=${jobId}`,\n `JOB_TOKEN=${jobToken}`,\n `PROXY_CACHE=${this.cachedMode ? 'true' : 'false'}`,\n `DEPENDABOT_API_URL=${dependabotApiUrl}`,\n `ACTIONS_ID_TOKEN_REQUEST_TOKEN=${process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN || ''}`,\n `ACTIONS_ID_TOKEN_REQUEST_URL=${process.env.ACTIONS_ID_TOKEN_REQUEST_URL || ''}`,\n ],\n Entrypoint: ['sh', '-c', '/usr/sbin/update-ca-certificates && /update-job-proxy'],\n\n HostConfig: {\n NetworkMode: internalNetworkName,\n ExtraHosts: ['host.docker.internal:host-gateway'], // needed for Docker on Linux\n },\n });\n\n await externalNetwork.connect({ Container: container.id });\n\n logger.info(`Created proxy container: ${container.id}`);\n return container;\n }\n\n private customCAPath(): string | undefined {\n if ('CUSTOM_CA_PATH' in process.env) {\n return process.env.CUSTOM_CA_PATH;\n }\n // default to node.js configuration\n return process.env.NODE_EXTRA_CA_CERTS;\n }\n}\n","","// biome-ignore-all lint/suspicious/noShadowRestrictedNames: Proxy is okay\n\nimport type { FileFetcherInput, FileUpdaterInput } from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\nimport type Docker from 'dockerode';\nimport type { Container } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport type { JobParameters } from './params';\nimport type { Proxy } from './proxy';\nimport { extractUpdaterSha } from './utils';\n\nexport const JOB_INPUT_FILENAME = 'job.json';\nexport const JOB_INPUT_PATH = `/home/dependabot/dependabot-updater`;\nexport const REPO_CONTENTS_PATH = '/home/dependabot/dependabot-updater/repo';\nexport const CA_CERT_INPUT_PATH = '/usr/local/share/ca-certificates';\nexport const CA_CERT_FILENAME = 'dbot-ca.crt';\nconst UPDATER_MAX_MEMORY = 8 * 1024 * 1024 * 1024; // 8GB in bytes\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class UpdaterBuilder {\n constructor(\n private readonly docker: Docker,\n private readonly jobParams: JobParameters,\n private readonly input: FileFetcherInput | FileUpdaterInput,\n private readonly proxy: Proxy,\n\n private readonly updaterImage: string,\n ) {}\n\n async run(containerName: string): Promise<Container> {\n const proxyUrl = await this.proxy.url();\n const updaterSha = extractUpdaterSha(this.updaterImage);\n\n const envVars = [\n `GITHUB_ACTIONS=${process.env.GITHUB_ACTIONS}`,\n `DEPENDABOT_JOB_ID=${this.jobParams.jobId}`,\n `DEPENDABOT_JOB_TOKEN=`,\n `DEPENDABOT_JOB_PATH=${JOB_INPUT_PATH}/${JOB_INPUT_FILENAME}`,\n `DEPENDABOT_OPEN_TIMEOUT_IN_SECONDS=15`,\n `DEPENDABOT_REPO_CONTENTS_PATH=${REPO_CONTENTS_PATH}`,\n `DEPENDABOT_API_URL=${this.jobParams.dependabotApiDockerUrl}`,\n `SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt`,\n `http_proxy=${proxyUrl}`,\n `HTTP_PROXY=${proxyUrl}`,\n `https_proxy=${proxyUrl}`,\n `HTTPS_PROXY=${proxyUrl}`,\n `ENABLE_CONNECTIVITY_CHECK=${process.env.DEPENDABOT_ENABLE_CONNECTIVITY_CHECK || '1'}`,\n\n // for updates relying on .NET (e.g. NuGet) and running on macOS (e.g. dev laptop or local MacMini),\n // we need to disable WriteXorExecute to avoid issues with emulation of Linux containers on macOS hosts\n // with Apple Silicon (M1/M2) chips\n // See - https://github.com/dotnet/runtime/issues/103063#issuecomment-2149599940\n // - https://github.com/dependabot/dependabot-core/issues/5037\n ...(process.platform === 'darwin' ? [`DOTNET_EnableWriteXorExecute=0`] : []),\n ];\n\n // Add DEPENDABOT_UPDATER_SHA if we successfully extracted a SHA\n if (updaterSha !== null) {\n envVars.push(`DEPENDABOT_UPDATER_SHA=${updaterSha}`);\n }\n\n const container = await this.docker.createContainer({\n Image: this.updaterImage,\n name: containerName,\n AttachStdout: true,\n AttachStderr: true,\n User: 'dependabot',\n Env: envVars,\n Cmd: ['/bin/sh'],\n Tty: true,\n HostConfig: {\n Memory: UPDATER_MAX_MEMORY,\n NetworkMode: this.proxy.networkName,\n },\n });\n\n await ContainerService.storeCert(CA_CERT_FILENAME, CA_CERT_INPUT_PATH, container, this.proxy.cert);\n\n await ContainerService.storeInput(JOB_INPUT_FILENAME, JOB_INPUT_PATH, container, this.input);\n\n logger.info(`Created container: ${container.id}`);\n return container;\n }\n}\n","// biome-ignore-all lint/suspicious/noShadowRestrictedNames: Proxy is okay\n\nimport type {\n DependabotCredential,\n DependabotJobConfig,\n FileFetcherInput,\n FileUpdaterInput,\n} from '@paklo/core/dependabot';\nimport Docker, { type Container } from 'dockerode';\nimport { ContainerService } from './container-service';\nimport type { JobParameters } from './params';\nimport { type Proxy, ProxyBuilder } from './proxy';\nimport { UpdaterBuilder } from './updater-builder';\n\n// Code below is borrowed and adapted from dependabot-action\n\nexport class Updater {\n docker: Docker;\n\n constructor(\n private readonly updaterImage: string,\n private readonly proxyImage: string,\n private readonly params: JobParameters,\n private readonly job: DependabotJobConfig,\n private readonly credentials: DependabotCredential[],\n private readonly debug: boolean,\n ) {\n this.docker = new Docker();\n this.job['credentials-metadata'] = this.generateCredentialsMetadata();\n }\n\n /**\n * Execute an update job and report the result to Dependabot API.\n */\n async runUpdater(): Promise<boolean> {\n const cachedMode = Object.hasOwn(this.job.experiments, 'proxy-cached') === true;\n\n const proxyBuilder = new ProxyBuilder(this.docker, this.proxyImage, cachedMode, this.debug);\n\n const proxy = await proxyBuilder.run(\n this.params.jobId,\n this.params.jobToken,\n this.params.dependabotApiUrl,\n this.credentials,\n );\n await proxy.container.start();\n\n try {\n await this.runUpdate(proxy);\n return true;\n } finally {\n await this.cleanup(proxy);\n }\n }\n\n private generateCredentialsMetadata(): DependabotCredential[] {\n const unique: Set<string> = new Set();\n const result: DependabotCredential[] = [];\n for (const credential of this.credentials) {\n if (credential.type === 'jit_access') {\n continue;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: necessary\n const obj: any = { type: credential.type };\n if (credential.host !== undefined) {\n obj.host = credential.host;\n }\n if (credential.registry !== undefined) {\n obj.registry = credential.registry;\n }\n if (credential.url !== undefined) {\n obj.url = credential.url;\n }\n this.setRegistryFromUrl(obj, credential);\n if (credential['index-url'] !== undefined) {\n obj['index-url'] = credential['index-url'];\n }\n this.setIndexUrlFromUrl(obj, credential);\n if (credential['env-key'] !== undefined) {\n obj['env-key'] = credential['env-key'];\n }\n if (credential.organization !== undefined) {\n obj.organization = credential.organization;\n }\n if (credential['replaces-base'] !== undefined) {\n obj['replaces-base'] = credential['replaces-base'];\n }\n if (credential['public-key-fingerprint'] !== undefined) {\n obj['public-key-fingerprint'] = credential['public-key-fingerprint'];\n }\n if (credential.repo !== undefined) {\n obj.repo = credential.repo;\n }\n const key = JSON.stringify(obj);\n if (!unique.has(key)) {\n unique.add(key);\n result.push(obj as DependabotCredential);\n }\n }\n return result;\n }\n\n private setRegistryFromUrl(obj: DependabotCredential, credential: DependabotCredential): void {\n const typesThatUseRegistryAsHost = ['npm_registry', 'composer_repository', 'docker_registry'];\n\n if (!typesThatUseRegistryAsHost.includes(credential.type)) {\n return;\n }\n\n if (!credential.registry && credential.url) {\n try {\n const parsedURL = new URL(credential.url);\n obj.registry = parsedURL.hostname;\n if (credential.type === 'npm_registry') {\n obj.registry += parsedURL.pathname;\n }\n } catch {\n // If the URL is invalid, we skip setting the registry\n // as it will fall back to the default registry for the given type (e.g., npm, Docker, or Composer).\n }\n }\n }\n\n private setIndexUrlFromUrl(obj: DependabotCredential, credential: DependabotCredential): void {\n if (credential.type !== 'python_index') {\n return;\n }\n if (credential['index-url']) {\n return;\n }\n if (credential.url) {\n try {\n obj['index-url'] = credential.url;\n } catch {\n // If the URL is invalid, we skip setting the index-url\n // as it will fall back to the default index URL for pip.\n }\n }\n }\n\n private async runUpdate(proxy: Proxy): Promise<void> {\n const name = `dependabot-job-${this.params.jobId}`;\n const container = await this.createContainer(proxy, name, {\n job: this.job,\n });\n\n await ContainerService.run(container, this.job.command);\n }\n\n private async createContainer(\n proxy: Proxy,\n containerName: string,\n input: FileFetcherInput | FileUpdaterInput,\n ): Promise<Container> {\n const builder = new UpdaterBuilder(this.docker, this.params, input, proxy, this.updaterImage);\n return builder.run(containerName);\n }\n\n private async cleanup(proxy: Proxy): Promise<void> {\n await proxy.shutdown();\n }\n}\n","import crypto from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport os from 'node:os';\nimport { logger } from '@paklo/core/logger';\nimport type { UsageTelemetryRequestData } from '@paklo/core/usage';\nimport ky from 'ky';\nimport { z } from 'zod';\n\nimport packageJson from '../package.json';\nimport { ApiClient, CredentialFetchingError, type SecretMasker } from './api-client';\nimport { PROXY_IMAGE_NAME, updaterImageName } from './docker-tags';\nimport { ImageService, type MetricReporter } from './image-service';\nimport { getJobParameters } from './params';\nimport { Updater } from './updater';\n\nexport class JobRunnerImagingError extends Error {}\nexport class JobRunnerUpdaterError extends Error {}\n\nexport type RunJobOptions = {\n dependabotApiUrl: string;\n dependabotApiDockerUrl?: string;\n jobId: string;\n jobToken: string;\n credentialsToken: string;\n updaterImage?: string;\n secretMasker: SecretMasker;\n debug: boolean;\n usage: Pick<UsageTelemetryRequestData, 'trigger' | 'provider' | 'owner' | 'project' | 'package-manager'>;\n};\nexport type RunJobResult = { success: true; message?: string } | { success: false; message: string };\n\nexport async function runJob(options: RunJobOptions): Promise<RunJobResult> {\n const { jobId, dependabotApiUrl, dependabotApiDockerUrl, jobToken, credentialsToken, secretMasker, debug, usage } =\n options;\n\n const started = new Date();\n let success = false;\n let message: string | undefined;\n try {\n const params = getJobParameters({\n jobId,\n jobToken,\n credentialsToken,\n dependabotApiUrl,\n dependabotApiDockerUrl: dependabotApiDockerUrl ?? dependabotApiUrl,\n updaterImage: options.updaterImage,\n })!;\n\n const client = ky.create({ headers: { 'User-Agent': `paklo-runner/${packageJson.version}` } });\n const apiClient = new ApiClient(client, params, jobToken, credentialsToken, secretMasker);\n\n // If we fail to succeed in fetching the job details, we cannot be sure the job has entered a 'processing' state,\n // so we do not try attempt to report back an exception if this fails and instead rely on the workflow run\n // webhook as it anticipates scenarios where jobs have failed while 'enqueued'.\n const job = await apiClient.getJobDetails();\n\n // The params can specify which updater image to use. If it doesn't, fall back to the pinned version.\n const updaterImage = params.updaterImage || updaterImageName(job['package-manager']);\n\n // The sendMetrics function is used to send metrics to the API client.\n // It uses the package manager as a tag to identify the metric.\n const sendMetricsWithPackageManager: MetricReporter = async (name, metricType, value, additionalTags = {}) => {\n try {\n await apiClient.sendMetrics(name, metricType, value, {\n package_manager: job['package-manager'],\n ...additionalTags,\n });\n } catch (error) {\n logger.warn(`Metric sending failed for ${name}: ${(error as Error).message}`);\n }\n };\n\n const credentials = (await apiClient.getCredentials()) || [];\n\n const updater = new Updater(updaterImage, PROXY_IMAGE_NAME, params, job, credentials, debug);\n\n try {\n // Using sendMetricsWithPackageManager wrapper to inject package manager tag to\n // avoid passing additional parameters to ImageService.pull method\n await ImageService.pull(updaterImage, sendMetricsWithPackageManager);\n await ImageService.pull(PROXY_IMAGE_NAME, sendMetricsWithPackageManager);\n } catch (err: unknown) {\n if (err instanceof Error) {\n throw new JobRunnerImagingError(err.message);\n }\n }\n\n try {\n await updater.runUpdater();\n } catch (err: unknown) {\n if (err instanceof Error) {\n throw new JobRunnerUpdaterError(err.message);\n }\n }\n success = true;\n } catch (err) {\n if (err instanceof JobRunnerImagingError) {\n message = `Error fetching updater images: ${err.message}`;\n } else if (err instanceof JobRunnerUpdaterError) {\n message = `Error running updater: ${err.message}`;\n } else if (err instanceof CredentialFetchingError) {\n message = `Dependabot was unable to retrieve job credentials: ${err.message}`;\n } else {\n message = `Unknown error: ${(err as Error).message}`;\n }\n }\n\n // send usage telemetry, unless explicitly disabled\n const telemetryDisabled = z.stringbool().optional().parse(process.env.PAKLO_TELEMETRY_DISABLED);\n if (!telemetryDisabled) {\n // detect if we are running inside a Docker container\n const inDocker = await isRunningInDocker();\n const duration = Date.now() - started.getTime();\n const data: UsageTelemetryRequestData = {\n ...usage,\n host: {\n platform: os.platform(),\n release: os.release(),\n arch: os.arch(),\n 'machine-hash': crypto.createHash('sha256').update(os.hostname()).digest('hex'),\n 'docker-container': inDocker,\n },\n version: packageJson.version,\n id: jobId,\n started,\n duration,\n success,\n // error message but truncate to first 1000 characters to avoid sending too much data\n error: message ? { message: message.substring(0, 1000) } : undefined,\n };\n try {\n const json = JSON.stringify(data);\n logger.debug(`Usage telemetry data: ${json}`);\n const resp = await ky.post('https://www.paklo.app/api/usage-telemetry', {\n headers: { 'Content-Type': 'application/json' },\n body: json,\n });\n if (!resp.ok) {\n logger.debug(`Failed to send usage telemetry data: ${resp.status} ${resp.statusText}`);\n }\n } catch (err) {\n logger.debug(`Failed to send usage telemetry data: ${(err as Error).message}`);\n // ignore\n }\n } else {\n logger.debug('Telemetry disabled, not sending usage telemetry data');\n }\n\n logger.info(`Update job ${jobId} completed`);\n return { success, message: message! };\n}\n\n/**\n * Detects if the current process is running inside a Docker container.\n */\nexport async function isRunningInDocker(): Promise<boolean> {\n // Check for .dockerenv file\n if (existsSync('/.dockerenv')) return true;\n\n // Check cgroup\n try {\n const cgroup = await readFile('/proc/self/cgroup', 'utf8');\n return cgroup.includes('docker') || cgroup.includes('kubepods');\n } catch {\n return false;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server-BxUu1gGo.mjs","names":[],"sources":["../src/local/runner.ts","../src/local/server.ts"],"sourcesContent":["import type { DependabotConfig, DependabotExperiments, DependabotJobConfig } from '@paklo/core/dependabot';\nimport { Keygen } from '@paklo/core/keygen';\nimport type { SecretMasker } from '../api-client';\n\nexport type RunJobsResult = { id: string; success: boolean; message?: string; affectedPrs: number[] }[];\n\nexport type LocalJobsRunnerOptions = {\n jobTokenOverride?: string;\n credentialsTokenOverride?: string;\n secretMasker: SecretMasker;\n\n config: DependabotConfig;\n targetUpdateIds?: number[];\n experiments: DependabotExperiments;\n updaterImage?: string;\n command?: DependabotJobConfig['command'];\n};\n\nexport abstract class LocalJobsRunner {\n private readonly opt: LocalJobsRunnerOptions;\n\n constructor(options: LocalJobsRunnerOptions) {\n this.opt = options;\n }\n\n protected makeTokens() {\n const { jobTokenOverride, credentialsTokenOverride } = this.opt;\n return {\n jobToken: jobTokenOverride ?? Keygen.generate(),\n credentialsToken: credentialsTokenOverride ?? Keygen.generate(),\n };\n }\n\n public run(): Promise<RunJobsResult> {\n return Promise.resolve([{ id: '-1', success: false, affectedPrs: [] }]);\n }\n}\n","import type { AddressInfo } from 'node:net';\nimport { createAdaptorServer } from '@hono/node-server';\nimport {\n type CreateApiServerAppOptions,\n createApiServerApp,\n type DependabotCredential,\n type DependabotJobConfig,\n type DependabotRequest,\n type DependabotTokenType,\n type DependabotUpdate,\n type GitAuthor,\n} from '@paklo/core/dependabot';\nimport { logger } from '@paklo/core/logger';\n\nexport type LocalDependabotServerAddOptions = {\n /** The ID of the dependabot job. */\n id: string;\n /** The dependabot update associated with the job. */\n update: DependabotUpdate;\n /** The dependabot job configuration. */\n job: DependabotJobConfig;\n /** The authentication token for the job. */\n jobToken: string;\n /** The authentication token for the job. */\n credentialsToken: string;\n /** The credentials associated with the job. */\n credentials: DependabotCredential[];\n};\n\nexport type AffectedPullRequestIds = {\n created: number[];\n updated: number[];\n closed: number[];\n};\n\nexport type LocalDependabotServerOptions = Omit<\n CreateApiServerAppOptions,\n 'authenticate' | 'getJob' | 'getCredentials' | 'handle'\n> & {\n author: GitAuthor;\n debug: boolean;\n dryRun: boolean;\n};\nexport abstract class LocalDependabotServer {\n private readonly hostname = 'localhost';\n private readonly server: ReturnType<typeof createAdaptorServer>;\n private readonly trackedJobs = new Map<string, DependabotJobConfig>();\n private readonly updates = new Map<string, DependabotUpdate>();\n private readonly jobTokens = new Map<string, string>();\n private readonly credentialTokens = new Map<string, string>();\n private readonly jobCredentials = new Map<string, DependabotCredential[]>();\n private readonly receivedRequests = new Map<string, DependabotRequest[]>();\n\n protected readonly affectedPullRequestIds = new Map<string, AffectedPullRequestIds>();\n\n constructor(options: LocalDependabotServerOptions) {\n const app = createApiServerApp({\n ...options,\n authenticate: this.authenticate.bind(this),\n getJob: this.job.bind(this),\n getCredentials: this.credentials.bind(this),\n handle: this.handle.bind(this),\n });\n this.server = createAdaptorServer({\n ...app,\n // Workaround for hono not respecting x-forwarded-proto header\n // https://github.com/honojs/node-server/issues/146#issuecomment-3153435672\n fetch: (req) => {\n const url = new URL(req.url);\n url.protocol = req.headers.get('x-forwarded-proto') ?? url.protocol;\n return app.fetch(new Request(url, req));\n },\n });\n }\n\n start(port?: number) {\n // listening to 'localhost' will result to IpV6 only but we need it to be all local\n // interfaces, otherwise containers cannot reach it using host.docker.internal\n this.server.listen(port, '0.0.0.0', () => {\n const info = this.server.address() as AddressInfo;\n logger.info(`API server listening on http://${this.hostname}:${info.port}`);\n });\n }\n\n stop() {\n this.server.close(() => logger.info('API server closed'));\n }\n\n get url() {\n const info = this.server.address() as AddressInfo;\n return `http://${this.hostname}:${info.port}`;\n }\n\n get port() {\n const info = this.server.address() as AddressInfo;\n return info.port;\n }\n\n get jobs() {\n return this.trackedJobs;\n }\n\n /**\n * Adds a dependabot job.\n * @param value - The dependabot job details.\n */\n add(value: LocalDependabotServerAddOptions) {\n const { id, update, job, jobToken, credentialsToken, credentials } = value;\n const {\n trackedJobs,\n updates,\n jobTokens,\n credentialTokens,\n jobCredentials,\n receivedRequests,\n affectedPullRequestIds,\n } = this;\n trackedJobs.set(id, job);\n updates.set(id, update);\n jobTokens.set(id, jobToken);\n credentialTokens.set(id, credentialsToken);\n jobCredentials.set(id, credentials);\n receivedRequests.set(id, []);\n affectedPullRequestIds.set(id, { created: [], updated: [], closed: [] });\n }\n\n /**\n * Gets a dependabot job by ID.\n * @param id - The ID of the dependabot job to get.\n * @returns The dependabot job, or undefined if not found.\n */\n job(id: string): Promise<DependabotJobConfig | undefined> {\n return Promise.resolve(this.trackedJobs.get(id));\n }\n\n /**\n * Gets a dependabot update by ID of the job.\n * @param id - The ID of the dependabot job to get.\n * @returns The dependabot update, or undefined if not found.\n */\n update(id: string): DependabotUpdate | undefined {\n return this.updates.get(id);\n }\n\n /**\n * Gets a token by ID of the job.\n * @param id - The ID of the dependabot job to get.\n * @returns The job token, or undefined if not found.\n */\n token(id: string, type: DependabotTokenType): string | undefined {\n return type === 'job' ? this.jobTokens.get(id) : this.credentialTokens.get(id);\n }\n\n /**\n * Gets the credentials for a dependabot job by ID.\n * @param id - The ID of the dependabot job to get credentials for.\n * @returns The credentials for the job, or undefined if not found.\n */\n credentials(id: string): Promise<DependabotCredential[] | undefined> {\n return Promise.resolve(this.jobCredentials.get(id));\n }\n\n /**\n * Gets the received requests for a dependabot job by ID.\n * @param id - The ID of the dependabot job to get requests for.\n * @returns The received requests for the job, or undefined if not found.\n */\n requests(id: string): DependabotRequest[] | undefined {\n return this.receivedRequests.get(id);\n }\n\n /**\n * Gets the IDs of pull requests affected by a dependabot job by ID.\n * @param id - The ID of the dependabot job to get affected pull request IDs for.\n * @returns The affected pull request IDs for the job, or undefined if not found.\n */\n affectedPrs(id: string): AffectedPullRequestIds | undefined {\n const { affectedPullRequestIds } = this;\n return affectedPullRequestIds.get(id);\n }\n\n /**\n * Gets all IDs of pull requests affected by a dependabot job by ID.\n * @param id - The ID of the dependabot job to get affected pull request IDs for.\n * @returns The affected pull request IDs for the job, or undefined if not found.\n */\n allAffectedPrs(id: string): number[] {\n const affected = this.affectedPrs(id);\n if (!affected) return [];\n return [...affected.created, ...affected.updated, ...affected.closed];\n }\n\n /**\n * Clears all data associated with a dependabot job by ID.\n * This should be called when the job is no longer needed.\n * @param id - The ID of the dependabot job to clear.\n */\n clear(id: string) {\n this.trackedJobs.delete(id);\n this.updates.delete(id);\n this.jobTokens.delete(id);\n this.credentialTokens.delete(id);\n this.jobCredentials.delete(id);\n this.receivedRequests.delete(id);\n this.affectedPullRequestIds.delete(id);\n }\n\n /**\n * Authenticates a dependabot job.\n * @param id - The ID of the dependabot job.\n * @param value - The authentication value (e.g., API key).\n * @returns A promise that resolves to a boolean indicating whether the authentication was successful.\n */\n protected async authenticate(type: DependabotTokenType, id: string, value: string): Promise<boolean> {\n const token = type === 'job' ? this.jobTokens.get(id) : this.credentialTokens.get(id);\n if (!token) {\n logger.debug(`Authentication failed: ${type} token ${id} not found`);\n return false;\n }\n if (token !== value) {\n logger.debug(`Authentication failed: invalid token for ${type} token ${id}`);\n return false;\n }\n return true;\n }\n\n /**\n * Handles a dependabot request.\n * @param id - The ID of the dependabot job.\n * @param request - The dependabot request to handle.\n * @returns A promise that resolves to the result of handling the request.\n */\n protected handle(id: string, request: DependabotRequest): Promise<boolean> {\n this.receivedRequests.get(id)!.push(request);\n return Promise.resolve(true);\n }\n}\n"],"mappings":"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"}
|