@paklo/runner 0.1.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/LICENSE +21 -0
- package/dist/index.d.ts +167 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/job-runner-BUl_fCJS.js +770 -0
- package/dist/job-runner-BUl_fCJS.js.map +1 -0
- package/dist/local/azure.d.ts +53 -0
- package/dist/local/azure.js +424 -0
- package/dist/local/azure.js.map +1 -0
- package/dist/local/index.d.ts +2 -0
- package/dist/local/index.js +4 -0
- package/dist/logger-Bekleunx.js +3 -0
- package/dist/server-Dcc7bD60.js +203 -0
- package/dist/server-Dcc7bD60.js.map +1 -0
- package/dist/server-Ri18zAcc.d.ts +229 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Maxwell Weru
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { DependabotCredential, DependabotJobConfig, DependabotMetric, DependabotProxyConfig, DependabotRecordUpdateJobError, FileFetcherInput, FileUpdaterInput } from "@paklo/core/dependabot";
|
|
2
|
+
import { InnerApiClient } from "@paklo/core/http";
|
|
3
|
+
import Docker, { Container, Network } from "dockerode";
|
|
4
|
+
import { UsageTelemetryRequestData } from "@paklo/core/usage";
|
|
5
|
+
|
|
6
|
+
//#region src/params.d.ts
|
|
7
|
+
declare class JobParameters {
|
|
8
|
+
readonly jobId: number;
|
|
9
|
+
readonly jobToken: string;
|
|
10
|
+
readonly credentialsToken: string;
|
|
11
|
+
readonly dependabotApiUrl: string;
|
|
12
|
+
readonly dependabotApiDockerUrl: string;
|
|
13
|
+
readonly updaterImage: string;
|
|
14
|
+
constructor(jobId: number, jobToken: string, credentialsToken: string, dependabotApiUrl: string, dependabotApiDockerUrl: string, updaterImage: string);
|
|
15
|
+
}
|
|
16
|
+
declare function getJobParameters(input: {
|
|
17
|
+
jobId?: string | number;
|
|
18
|
+
jobToken?: string;
|
|
19
|
+
credentialsToken?: string;
|
|
20
|
+
dependabotApiUrl?: string;
|
|
21
|
+
dependabotApiDockerUrl?: string;
|
|
22
|
+
updaterImage?: string;
|
|
23
|
+
}): JobParameters | null;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/api-client.d.ts
|
|
26
|
+
declare class JobDetailsFetchingError extends Error {}
|
|
27
|
+
declare class CredentialFetchingError extends Error {}
|
|
28
|
+
type SecretMasker = (value: string) => void;
|
|
29
|
+
declare class ApiClient {
|
|
30
|
+
private readonly client;
|
|
31
|
+
readonly params: JobParameters;
|
|
32
|
+
private readonly credentialsToken;
|
|
33
|
+
private readonly secretMasker;
|
|
34
|
+
private jobToken;
|
|
35
|
+
constructor(client: InnerApiClient, params: JobParameters, jobToken: string, credentialsToken: string, secretMasker: SecretMasker);
|
|
36
|
+
UnknownSha: {
|
|
37
|
+
'base-commit-sha': string;
|
|
38
|
+
};
|
|
39
|
+
getJobToken(): string;
|
|
40
|
+
getJobDetails(): Promise<DependabotJobConfig>;
|
|
41
|
+
getCredentials(): Promise<DependabotCredential[]>;
|
|
42
|
+
reportJobError(error: DependabotRecordUpdateJobError): Promise<void>;
|
|
43
|
+
markJobAsProcessed(): Promise<void>;
|
|
44
|
+
sendMetrics(name: string, metricType: 'increment' | 'gauge', value: number, additionalTags?: Record<string, string>): Promise<void>;
|
|
45
|
+
reportMetrics(metrics: DependabotMetric[]): Promise<void>;
|
|
46
|
+
private getWithRetry;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/cleanup.d.ts
|
|
50
|
+
declare function cleanup(cutoff?: string): Promise<void>;
|
|
51
|
+
declare function cleanupOldImageVersions(docker: Docker, imageName: string): Promise<void>;
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/container-service.d.ts
|
|
54
|
+
declare class ContainerRuntimeError extends Error {}
|
|
55
|
+
declare const ContainerService: {
|
|
56
|
+
storeInput(name: string, path: string, container: Container, input: FileFetcherInput | FileUpdaterInput | DependabotProxyConfig): Promise<void>;
|
|
57
|
+
storeCert(name: string, path: string, container: Container, cert: string): Promise<void>;
|
|
58
|
+
run(container: Container, command?: string): Promise<boolean>;
|
|
59
|
+
execCommand(container: Container, cmd: string[], user: string): Promise<void>;
|
|
60
|
+
};
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/docker-tags.d.ts
|
|
63
|
+
declare const PROXY_IMAGE_NAME: string;
|
|
64
|
+
declare function updaterImageName(packageManager: string): string;
|
|
65
|
+
declare function updaterImages(): string[];
|
|
66
|
+
declare function repositoryName(imageName: string): string;
|
|
67
|
+
declare function hasDigest(imageName: string): boolean;
|
|
68
|
+
declare function digestName(imageName: string): string;
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/image-service.d.ts
|
|
71
|
+
declare function getOrgFromImage(imageName: string): string;
|
|
72
|
+
type MetricReporter = (metricName: string, metricType: 'increment' | 'gauge', value: number, additionalTags?: Record<string, string>) => Promise<void>;
|
|
73
|
+
/** Fetch the configured updater image, if it isn't already available. */
|
|
74
|
+
declare const ImageService: {
|
|
75
|
+
pull(imageName: string, sendMetric?: MetricReporter, force?: boolean): Promise<void>;
|
|
76
|
+
fetchImageWithRetry(imageName: string, auth: {} | undefined, docker: Docker | undefined, sendMetric: MetricReporter | undefined, org: string): Promise<void>;
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/job-runner.d.ts
|
|
80
|
+
declare class JobRunnerImagingError extends Error {}
|
|
81
|
+
declare class JobRunnerUpdaterError extends Error {}
|
|
82
|
+
type JobRunnerOptions = {
|
|
83
|
+
dependabotApiUrl: string;
|
|
84
|
+
dependabotApiDockerUrl?: string;
|
|
85
|
+
jobId: number;
|
|
86
|
+
jobToken: string;
|
|
87
|
+
credentialsToken: string;
|
|
88
|
+
updaterImage?: string;
|
|
89
|
+
secretMasker: SecretMasker;
|
|
90
|
+
};
|
|
91
|
+
declare class JobRunner {
|
|
92
|
+
private readonly options;
|
|
93
|
+
constructor(options: JobRunnerOptions);
|
|
94
|
+
run(): Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
type RunJobOptions = JobRunnerOptions & {
|
|
97
|
+
usage: Pick<UsageTelemetryRequestData, 'trigger' | 'provider' | 'owner' | 'project' | 'package-manager'>;
|
|
98
|
+
};
|
|
99
|
+
type RunJobResult = {
|
|
100
|
+
success: true;
|
|
101
|
+
message?: string;
|
|
102
|
+
} | {
|
|
103
|
+
success: false;
|
|
104
|
+
message: string;
|
|
105
|
+
};
|
|
106
|
+
declare function runJob({
|
|
107
|
+
jobId,
|
|
108
|
+
usage,
|
|
109
|
+
...options
|
|
110
|
+
}: RunJobOptions): Promise<RunJobResult>;
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region src/proxy.d.ts
|
|
113
|
+
type Proxy = {
|
|
114
|
+
container: Container;
|
|
115
|
+
network: Network;
|
|
116
|
+
networkName: string;
|
|
117
|
+
url: () => Promise<string>;
|
|
118
|
+
cert: string;
|
|
119
|
+
shutdown: () => Promise<void>;
|
|
120
|
+
};
|
|
121
|
+
declare class ProxyBuilder {
|
|
122
|
+
private readonly docker;
|
|
123
|
+
private readonly proxyImage;
|
|
124
|
+
private readonly cachedMode;
|
|
125
|
+
constructor(docker: Docker, proxyImage: string, cachedMode: boolean);
|
|
126
|
+
run(jobId: number, jobToken: string, dependabotApiUrl: string, credentials: DependabotCredential[]): Promise<Proxy>;
|
|
127
|
+
private ensureNetwork;
|
|
128
|
+
private buildProxyConfig;
|
|
129
|
+
private generateCertificateAuthority;
|
|
130
|
+
private createContainer;
|
|
131
|
+
private customCAPath;
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/updater.d.ts
|
|
135
|
+
declare class Updater {
|
|
136
|
+
private readonly updaterImage;
|
|
137
|
+
private readonly proxyImage;
|
|
138
|
+
private readonly params;
|
|
139
|
+
private readonly job;
|
|
140
|
+
private readonly credentials;
|
|
141
|
+
docker: Docker;
|
|
142
|
+
constructor(updaterImage: string, proxyImage: string, params: JobParameters, job: DependabotJobConfig, credentials: DependabotCredential[]);
|
|
143
|
+
/**
|
|
144
|
+
* Execute an update job and report the result to Dependabot API.
|
|
145
|
+
*/
|
|
146
|
+
runUpdater(): Promise<boolean>;
|
|
147
|
+
private generateCredentialsMetadata;
|
|
148
|
+
private setRegistryFromUrl;
|
|
149
|
+
private setIndexUrlFromUrl;
|
|
150
|
+
private runUpdate;
|
|
151
|
+
private createContainer;
|
|
152
|
+
private cleanup;
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region src/updater-builder.d.ts
|
|
156
|
+
declare class UpdaterBuilder {
|
|
157
|
+
private readonly docker;
|
|
158
|
+
private readonly jobParams;
|
|
159
|
+
private readonly input;
|
|
160
|
+
private readonly proxy;
|
|
161
|
+
private readonly updaterImage;
|
|
162
|
+
constructor(docker: Docker, jobParams: JobParameters, input: FileFetcherInput | FileUpdaterInput, proxy: Proxy, updaterImage: string);
|
|
163
|
+
run(containerName: string): Promise<Container>;
|
|
164
|
+
}
|
|
165
|
+
//#endregion
|
|
166
|
+
export { ApiClient, ContainerRuntimeError, ContainerService, CredentialFetchingError, ImageService, JobDetailsFetchingError, JobParameters, JobRunner, JobRunnerImagingError, JobRunnerOptions, JobRunnerUpdaterError, MetricReporter, PROXY_IMAGE_NAME, Proxy, ProxyBuilder, RunJobOptions, RunJobResult, SecretMasker, Updater, UpdaterBuilder, cleanup, cleanupOldImageVersions, digestName, getJobParameters, getOrgFromImage, hasDigest, repositoryName, runJob, updaterImageName, updaterImages };
|
|
167
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { t as logger } from "./logger-Bekleunx.js";
|
|
2
|
+
import { S as JobDetailsFetchingError, _ as repositoryName, a as Updater, b as ApiClient, c as JobParameters, d as getOrgFromImage, f as ContainerRuntimeError, g as hasDigest, h as digestName, i as runJob, l as getJobParameters, m as PROXY_IMAGE_NAME, n as JobRunnerImagingError, o as UpdaterBuilder, p as ContainerService, r as JobRunnerUpdaterError, s as ProxyBuilder, t as JobRunner, u as ImageService, v as updaterImageName, x as CredentialFetchingError, y as updaterImages } from "./job-runner-BUl_fCJS.js";
|
|
3
|
+
import Docker from "dockerode";
|
|
4
|
+
|
|
5
|
+
//#region src/cleanup.ts
|
|
6
|
+
async function cleanup(cutoff = "24h") {
|
|
7
|
+
if (process.env.DEPENDABOT_DISABLE_CLEANUP === "1") return;
|
|
8
|
+
try {
|
|
9
|
+
const docker = new Docker();
|
|
10
|
+
const untilFilter = { until: [cutoff] };
|
|
11
|
+
logger.info(`Pruning networks older than ${cutoff}`);
|
|
12
|
+
await docker.pruneNetworks({ filters: untilFilter });
|
|
13
|
+
logger.info(`Pruning containers older than ${cutoff}`);
|
|
14
|
+
await docker.pruneContainers({ filters: untilFilter });
|
|
15
|
+
await Promise.all(updaterImages().map(async (image) => {
|
|
16
|
+
return cleanupOldImageVersions(docker, image);
|
|
17
|
+
}));
|
|
18
|
+
await cleanupOldImageVersions(docker, PROXY_IMAGE_NAME);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
if (error instanceof Error) logger.error(`Error cleaning up: ${error.message}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function cleanupOldImageVersions(docker, imageName) {
|
|
24
|
+
const repo = repositoryName(imageName);
|
|
25
|
+
const options = { filters: `{"reference":["${repo}"]}` };
|
|
26
|
+
logger.info(`Cleaning up images for ${repo}`);
|
|
27
|
+
docker.listImages(options, async (err, imageInfoList) => {
|
|
28
|
+
if (imageInfoList && imageInfoList.length > 0) for (const imageInfo of imageInfoList) {
|
|
29
|
+
if (imageMatches(imageInfo, imageName)) {
|
|
30
|
+
logger.info(`Skipping current image ${imageInfo.Id}`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
logger.info(`Removing image ${imageInfo.Id}`);
|
|
34
|
+
try {
|
|
35
|
+
await docker.getImage(imageInfo.Id).remove();
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (error instanceof Error) logger.info(`Unable to remove ${imageInfo.Id} -- ${error.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function imageMatches(imageInfo, imageName) {
|
|
43
|
+
if (hasDigest(imageName)) return imageInfo.RepoDigests ? imageInfo.RepoDigests.includes(digestName(imageName)) : false;
|
|
44
|
+
return imageInfo.RepoTags ? imageInfo.RepoTags.includes(imageName) : false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
export { ApiClient, ContainerRuntimeError, ContainerService, CredentialFetchingError, ImageService, JobDetailsFetchingError, JobParameters, JobRunner, JobRunnerImagingError, JobRunnerUpdaterError, PROXY_IMAGE_NAME, ProxyBuilder, Updater, UpdaterBuilder, cleanup, cleanupOldImageVersions, digestName, getJobParameters, getOrgFromImage, hasDigest, repositoryName, runJob, updaterImageName, updaterImages };
|
|
49
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["error: unknown"],"sources":["../src/cleanup.ts"],"sourcesContent":["import Docker from 'dockerode';\nimport { logger } from '@/logger';\nimport { digestName, hasDigest, PROXY_IMAGE_NAME, repositoryName, updaterImages } from './docker-tags';\n\n// Code below is borrowed and adapted from dependabot-action\n\n// This method performs housekeeping checks to remove Docker artifacts\n// which were left behind by old versions or any jobs\n// which may have crashed before deleting their own containers or networks\n//\n// cutoff - a Go duration string to pass to the Docker API's 'until' argument, default '24h'\nexport async function cleanup(cutoff = '24h'): Promise<void> {\n if (process.env.DEPENDABOT_DISABLE_CLEANUP === '1') {\n return;\n }\n\n try {\n const docker = new Docker();\n const untilFilter = { until: [cutoff] };\n logger.info(`Pruning networks older than ${cutoff}`);\n await docker.pruneNetworks({ filters: untilFilter });\n logger.info(`Pruning containers older than ${cutoff}`);\n await docker.pruneContainers({ filters: untilFilter });\n await Promise.all(\n updaterImages().map(async (image) => {\n return cleanupOldImageVersions(docker, image);\n }),\n );\n await cleanupOldImageVersions(docker, PROXY_IMAGE_NAME);\n } catch (error: unknown) {\n if (error instanceof Error) {\n logger.error(`Error cleaning up: ${error.message}`);\n }\n }\n}\n\nexport async function cleanupOldImageVersions(docker: Docker, imageName: string): Promise<void> {\n const repo = repositoryName(imageName);\n const options = {\n filters: `{\"reference\":[\"${repo}\"]}`,\n };\n\n logger.info(`Cleaning up images for ${repo}`);\n\n docker.listImages(options, async (err, imageInfoList) => {\n if (imageInfoList && imageInfoList.length > 0) {\n for (const imageInfo of imageInfoList) {\n // The given imageName is expected to be a tag + digest, however to avoid any surprises in future\n // we fail over to check for a match on just tags as well.\n //\n // This means we won't remove any image which matches an imageName of either of these notations:\n // - dependabot/image:$TAG@sha256:$REF (current implementation)\n // - dependabot/image:v1\n //\n // Without checking imageInfo.RepoTags for a match, we would actually remove the latter even if\n // this was the active version.\n if (imageMatches(imageInfo, imageName)) {\n logger.info(`Skipping current image ${imageInfo.Id}`);\n continue;\n }\n\n logger.info(`Removing image ${imageInfo.Id}`);\n try {\n await docker.getImage(imageInfo.Id).remove();\n } catch (error: unknown) {\n if (error instanceof Error) {\n logger.info(`Unable to remove ${imageInfo.Id} -- ${error.message}`);\n }\n }\n }\n }\n });\n}\n\nfunction imageMatches(imageInfo: Docker.ImageInfo, imageName: string): boolean {\n if (hasDigest(imageName)) {\n return imageInfo.RepoDigests ? imageInfo.RepoDigests.includes(digestName(imageName)) : false;\n }\n return imageInfo.RepoTags ? imageInfo.RepoTags.includes(imageName) : false;\n}\n"],"mappings":";;;;;AAWA,eAAsB,QAAQ,SAAS,OAAsB;AAC3D,KAAI,QAAQ,IAAI,+BAA+B,IAC7C;AAGF,KAAI;EACF,MAAM,SAAS,IAAI,QAAQ;EAC3B,MAAM,cAAc,EAAE,OAAO,CAAC,OAAO,EAAE;AACvC,SAAO,KAAK,+BAA+B,SAAS;AACpD,QAAM,OAAO,cAAc,EAAE,SAAS,aAAa,CAAC;AACpD,SAAO,KAAK,iCAAiC,SAAS;AACtD,QAAM,OAAO,gBAAgB,EAAE,SAAS,aAAa,CAAC;AACtD,QAAM,QAAQ,IACZ,eAAe,CAAC,IAAI,OAAO,UAAU;AACnC,UAAO,wBAAwB,QAAQ,MAAM;IAC7C,CACH;AACD,QAAM,wBAAwB,QAAQ,iBAAiB;UAChDA,OAAgB;AACvB,MAAI,iBAAiB,MACnB,QAAO,MAAM,sBAAsB,MAAM,UAAU;;;AAKzD,eAAsB,wBAAwB,QAAgB,WAAkC;CAC9F,MAAM,OAAO,eAAe,UAAU;CACtC,MAAM,UAAU,EACd,SAAS,kBAAkB,KAAK,MACjC;AAED,QAAO,KAAK,0BAA0B,OAAO;AAE7C,QAAO,WAAW,SAAS,OAAO,KAAK,kBAAkB;AACvD,MAAI,iBAAiB,cAAc,SAAS,EAC1C,MAAK,MAAM,aAAa,eAAe;AAUrC,OAAI,aAAa,WAAW,UAAU,EAAE;AACtC,WAAO,KAAK,0BAA0B,UAAU,KAAK;AACrD;;AAGF,UAAO,KAAK,kBAAkB,UAAU,KAAK;AAC7C,OAAI;AACF,UAAM,OAAO,SAAS,UAAU,GAAG,CAAC,QAAQ;YACrCA,OAAgB;AACvB,QAAI,iBAAiB,MACnB,QAAO,KAAK,oBAAoB,UAAU,GAAG,MAAM,MAAM,UAAU;;;GAK3E;;AAGJ,SAAS,aAAa,WAA6B,WAA4B;AAC7E,KAAI,UAAU,UAAU,CACtB,QAAO,UAAU,cAAc,UAAU,YAAY,SAAS,WAAW,UAAU,CAAC,GAAG;AAEzF,QAAO,UAAU,WAAW,UAAU,SAAS,SAAS,UAAU,GAAG"}
|