containerify 3.1.0 → 3.1.2

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/README.md CHANGED
@@ -45,7 +45,7 @@ This will take the `nginx:alpine` image, and copy the files from `./dist/` into
45
45
 
46
46
  1. Create the repository in GitLab
47
47
  2. Login using your username and password, [CI-credentials](https://docs.gitlab.com/ee/ci/jobs/ci_job_token.html), or [obtain a token from GitLab](https://docs.gitlab.com/ee/api/container_registry.html#obtain-token-from-gitlab)
48
- 3. Example using CI-credentials `containerify --toToken "Basic $(echo -n '${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD}' | base64)" --to registry.gitlab.com/<Gitlab organisation>/<repository>:<tag>`
48
+ 3. Example using CI-credentials `containerify --toToken "Basic $(echo -n "${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD}" | base64)" --to registry.gitlab.com/<Gitlab organisation>/<repository>:<tag>`
49
49
 
50
50
  ### Command line options
51
51
 
package/lib/cli.js CHANGED
@@ -226,8 +226,8 @@ Object.keys(options.extraContent).forEach((k) => {
226
226
  exitWithErrorIf(!fs.existsSync(options.folder + k), "Could not find `" + k + "` in the folder " + options.folder);
227
227
  });
228
228
  function run(options) {
229
- var _a;
230
229
  return __awaiter(this, void 0, void 0, function* () {
230
+ var _a;
231
231
  if (!(yield fse.pathExists(options.folder)))
232
232
  throw new Error("No such folder: " + options.folder);
233
233
  const tmpdir = fs.mkdtempSync(path.join(os.tmpdir(), "containerify-"));
package/lib/fileutil.js CHANGED
@@ -9,7 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.ensureEmptyDir = exports.sizeOf = void 0;
12
+ exports.sizeOf = sizeOf;
13
+ exports.ensureEmptyDir = ensureEmptyDir;
13
14
  const fs_1 = require("fs");
14
15
  const fse = require("fs-extra");
15
16
  const fss = require("fs");
@@ -18,7 +19,6 @@ function sizeOf(file) {
18
19
  return (yield fs_1.promises.lstat(file)).size;
19
20
  });
20
21
  }
21
- exports.sizeOf = sizeOf;
22
22
  function ensureEmptyDir(path) {
23
23
  return __awaiter(this, void 0, void 0, function* () {
24
24
  if (fss.existsSync(path))
@@ -27,7 +27,6 @@ function ensureEmptyDir(path) {
27
27
  return path;
28
28
  });
29
29
  }
30
- exports.ensureEmptyDir = ensureEmptyDir;
31
30
  exports.default = {
32
31
  sizeOf,
33
32
  ensureEmptyDir,
@@ -1,6 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
1
  import * as https from "https";
5
2
  import * as http from "http";
6
3
  import { InsecureRegistrySupport } from "./types";
@@ -9,7 +9,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.followRedirects = exports.dlJson = exports.waitForResponseEnd = exports.toError = exports.request = exports.buildHeaders = exports.createHttpOptions = exports.isOk = exports.redirectCodes = void 0;
12
+ exports.redirectCodes = void 0;
13
+ exports.isOk = isOk;
14
+ exports.createHttpOptions = createHttpOptions;
15
+ exports.buildHeaders = buildHeaders;
16
+ exports.request = request;
17
+ exports.toError = toError;
18
+ exports.waitForResponseEnd = waitForResponseEnd;
19
+ exports.dlJson = dlJson;
20
+ exports.followRedirects = followRedirects;
13
21
  const https = require("https");
14
22
  const http = require("http");
15
23
  const URL = require("url");
@@ -19,21 +27,22 @@ exports.redirectCodes = [308, 307, 303, 302, 301];
19
27
  function isOk(httpStatus) {
20
28
  return httpStatus >= 200 && httpStatus < 300;
21
29
  }
22
- exports.isOk = isOk;
23
30
  function createHttpOptions(method, url, headers) {
24
31
  const options = Object.assign({}, URL.parse(url));
25
32
  options.headers = headers;
26
33
  options.method = method;
34
+ if (url.includes("X-Amz-Algorithm") && method == "GET") {
35
+ //We are using a pre-signed URL, so we don't need to send the Authorization header
36
+ options.headers["Authorization"] = "";
37
+ }
27
38
  return options;
28
39
  }
29
- exports.createHttpOptions = createHttpOptions;
30
40
  function buildHeaders(accept, auth) {
31
41
  const headers = { accept: accept };
32
42
  if (auth)
33
43
  headers.authorization = auth;
34
44
  return headers;
35
45
  }
36
- exports.buildHeaders = buildHeaders;
37
46
  function request(options, allowInsecure, callback) {
38
47
  if (allowInsecure == types_1.InsecureRegistrySupport.YES)
39
48
  options.rejectUnauthorized = false;
@@ -46,17 +55,14 @@ function request(options, allowInsecure, callback) {
46
55
  });
47
56
  return req;
48
57
  }
49
- exports.request = request;
50
58
  function toError(res) {
51
59
  return `Unexpected HTTP status ${res.statusCode} : ${res.statusMessage}`;
52
60
  }
53
- exports.toError = toError;
54
61
  function waitForResponseEnd(res, cb) {
55
62
  const data = [];
56
63
  res.on("data", (d) => data.push(d));
57
64
  res.on("end", () => cb(Buffer.concat(data)));
58
65
  }
59
- exports.waitForResponseEnd = waitForResponseEnd;
60
66
  function dl(uri, headers, allowInsecure) {
61
67
  logger_1.default.debug("dl", uri);
62
68
  return new Promise((resolve, reject) => {
@@ -66,9 +72,17 @@ function dl(uri, headers, allowInsecure) {
66
72
  return reject(result.error);
67
73
  const { res } = result;
68
74
  logger_1.default.debug(res.statusCode, res.statusMessage, res.headers["content-type"], res.headers["content-length"]);
69
- if (!isOk((_a = res.statusCode) !== null && _a !== void 0 ? _a : 0))
70
- return reject(toError(res));
71
- waitForResponseEnd(res, (data) => resolve(data.toString()));
75
+ if (!isOk((_a = res.statusCode) !== null && _a !== void 0 ? _a : 0)) {
76
+ const d = [];
77
+ res.on("data", (dt) => d.push(dt));
78
+ res.on("end", () => {
79
+ logger_1.default.error("ERROR", Buffer.concat(d).toString());
80
+ reject(toError(res));
81
+ });
82
+ }
83
+ else {
84
+ waitForResponseEnd(res, (data) => resolve(data.toString()));
85
+ }
72
86
  });
73
87
  });
74
88
  }
@@ -78,7 +92,6 @@ function dlJson(uri, headers, allowInsecure) {
78
92
  return JSON.parse(Buffer.from(data).toString("utf-8"));
79
93
  });
80
94
  }
81
- exports.dlJson = dlJson;
82
95
  function followRedirects(uri, headers, allowInsecure, cb, count = 0) {
83
96
  logger_1.default.debug("rc", uri);
84
97
  const options = createHttpOptions("GET", uri, headers);
@@ -88,6 +101,7 @@ function followRedirects(uri, headers, allowInsecure, cb, count = 0) {
88
101
  if (count > 10)
89
102
  return cb({ error: "Too many redirects for " + uri });
90
103
  const location = res.headers.location;
104
+ console.log(res.headers);
91
105
  if (!location)
92
106
  return cb({ error: "Redirect, but missing location header" });
93
107
  return followRedirects(location, headers, allowInsecure, cb, count + 1);
@@ -95,4 +109,3 @@ function followRedirects(uri, headers, allowInsecure, cb, count = 0) {
95
109
  cb({ res });
96
110
  }).end();
97
111
  }
98
- exports.followRedirects = followRedirects;
package/lib/registry.js CHANGED
@@ -9,7 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.parseFullImageUrl = exports.DEFAULT_DOCKER_REGISTRY = exports.createRegistry = void 0;
12
+ exports.DEFAULT_DOCKER_REGISTRY = void 0;
13
+ exports.createRegistry = createRegistry;
14
+ exports.parseFullImageUrl = parseFullImageUrl;
13
15
  const URL = require("url");
14
16
  const fss = require("fs");
15
17
  const fs_1 = require("fs");
@@ -130,19 +132,12 @@ function processToken(registryBaseUrl, allowInsecure, imagePath, token) {
130
132
  return __awaiter(this, void 0, void 0, function* () {
131
133
  const { hostname } = URL.parse(registryBaseUrl);
132
134
  const image = (0, utils_1.parseImage)(imagePath);
133
- if ((hostname === null || hostname === void 0 ? void 0 : hostname.endsWith(".docker.io")) && !token) {
134
- const resp = yield (0, httpRequest_1.dlJson)(`https://auth.docker.io/token?service=registry.docker.io&scope=repository:${image.path}:pull`, {}, allowInsecure);
135
- return `Bearer ${resp.token}`;
136
- }
137
- if ((hostname === null || hostname === void 0 ? void 0 : hostname.endsWith(".gitlab.com")) && (token === null || token === void 0 ? void 0 : token.startsWith("Basic"))) {
138
- if (token === null || token === void 0 ? void 0 : token.includes(":")) {
139
- token = "Basic " + Buffer.from(token === null || token === void 0 ? void 0 : token.replace("Basic ", "")).toString("base64");
140
- }
141
- const resp = yield (0, httpRequest_1.dlJson)(`https://gitlab.com/jwt/auth?service=container_registry&scope=repository:${image.path}:pull,push`, { Authorization: token }, allowInsecure);
142
- return `Bearer ${resp.token}`;
143
- }
135
+ if ((hostname === null || hostname === void 0 ? void 0 : hostname.endsWith(".docker.io")) && !token)
136
+ return getDockerToken(image.path, allowInsecure);
144
137
  if (!token)
145
138
  return ""; //We allow to pull from tokenless registries
139
+ if ((hostname === null || hostname === void 0 ? void 0 : hostname.endsWith(".gitlab.com")) && token.startsWith("Basic "))
140
+ return getGitLabToken(token, image.path, allowInsecure);
146
141
  if (token.startsWith("Basic "))
147
142
  return token;
148
143
  if (token.startsWith("ghp_"))
@@ -150,8 +145,23 @@ function processToken(registryBaseUrl, allowInsecure, imagePath, token) {
150
145
  return "Bearer " + token;
151
146
  });
152
147
  }
153
- function createRegistry(registryBaseUrl, imagePath, allowInsecure, auth, optimisticToRegistryCheck = false) {
148
+ function getDockerToken(imagePath, allowInsecure) {
149
+ return __awaiter(this, void 0, void 0, function* () {
150
+ const resp = yield (0, httpRequest_1.dlJson)(`https://auth.docker.io/token?service=registry.docker.io&scope=repository:${imagePath}:pull`, {}, allowInsecure);
151
+ return `Bearer ${resp.token}`;
152
+ });
153
+ }
154
+ function getGitLabToken(token, imagePath, allowInsecure) {
154
155
  return __awaiter(this, void 0, void 0, function* () {
156
+ if (token.includes(":")) {
157
+ token = "Basic " + Buffer.from(token.replace("Basic ", "")).toString("base64");
158
+ }
159
+ const resp = yield (0, httpRequest_1.dlJson)(`https://gitlab.com/jwt/auth?service=container_registry&scope=repository:${imagePath}:pull,push`, { Authorization: token }, allowInsecure);
160
+ return `Bearer ${resp.token}`;
161
+ });
162
+ }
163
+ function createRegistry(registryBaseUrl_1, imagePath_1, allowInsecure_1, auth_1) {
164
+ return __awaiter(this, arguments, void 0, function* (registryBaseUrl, imagePath, allowInsecure, auth, optimisticToRegistryCheck = false) {
155
165
  const token = yield processToken(registryBaseUrl, allowInsecure, imagePath, auth);
156
166
  function exists(image, layer) {
157
167
  return __awaiter(this, void 0, void 0, function* () {
@@ -166,15 +176,15 @@ function createRegistry(registryBaseUrl, imagePath, allowInsecure, auth, optimis
166
176
  yield uploadContent(uploadUrl, file, layer, allowInsecure, token);
167
177
  });
168
178
  }
169
- function getUploadUrl(image, mountParameters = undefined) {
170
- return __awaiter(this, void 0, void 0, function* () {
179
+ function getUploadUrl(image_1) {
180
+ return __awaiter(this, arguments, void 0, function* (image, mountParameters = undefined) {
171
181
  return new Promise((resolve, reject) => {
172
182
  const parameters = new URLSearchParams(mountParameters);
173
183
  const url = `${registryBaseUrl}${image.path}/blobs/uploads/${parameters.size > 0 ? "?" + parameters : ""}`;
174
184
  const options = URL.parse(url);
175
185
  options.method = "POST";
176
- if (auth)
177
- options.headers = { authorization: auth };
186
+ if (token)
187
+ options.headers = { authorization: token };
178
188
  (0, httpRequest_1.request)(options, allowInsecure, (res) => {
179
189
  logger_1.default.debug("POST", `${url}`, res.statusCode);
180
190
  if (res.statusCode == 202) {
@@ -329,7 +339,6 @@ function createRegistry(registryBaseUrl, imagePath, allowInsecure, auth, optimis
329
339
  };
330
340
  });
331
341
  }
332
- exports.createRegistry = createRegistry;
333
342
  exports.DEFAULT_DOCKER_REGISTRY = "https://registry-1.docker.io/v2/";
334
343
  function parseFullImageUrl(imageStr) {
335
344
  const [registry, ...rest] = imageStr.split("/");
@@ -344,4 +353,3 @@ function parseFullImageUrl(imageStr) {
344
353
  image: rest.join("/"),
345
354
  };
346
355
  }
347
- exports.parseFullImageUrl = parseFullImageUrl;
package/lib/utils.js CHANGED
@@ -1,15 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseImage = exports.getHash = exports.getLayerTypeFileEnding = exports.getManifestLayerType = exports.getPreferredPlatform = exports.omit = exports.unique = void 0;
3
+ exports.unique = unique;
4
+ exports.omit = omit;
5
+ exports.getPreferredPlatform = getPreferredPlatform;
6
+ exports.getManifestLayerType = getManifestLayerType;
7
+ exports.getLayerTypeFileEnding = getLayerTypeFileEnding;
8
+ exports.getHash = getHash;
9
+ exports.parseImage = parseImage;
4
10
  const MIMETypes_1 = require("./MIMETypes");
5
11
  function unique(vals) {
6
12
  return [...new Set(vals)];
7
13
  }
8
- exports.unique = unique;
9
14
  function omit(obj, keys) {
10
15
  return Object.fromEntries(Object.entries(obj).filter(([k]) => !keys.includes(k)));
11
16
  }
12
- exports.omit = omit;
13
17
  function getPreferredPlatform(platform) {
14
18
  var _a, _b;
15
19
  // We assume the input is similar to docker which accepts `<os>/<arch>` and `<arch>`
@@ -68,7 +72,6 @@ function getPreferredPlatform(platform) {
68
72
  architecture: targetArch,
69
73
  };
70
74
  }
71
- exports.getPreferredPlatform = getPreferredPlatform;
72
75
  function getManifestLayerType(manifest) {
73
76
  if (manifest.mediaType === MIMETypes_1.OCI.manifest) {
74
77
  return MIMETypes_1.OCI.layer.gzip;
@@ -78,7 +81,6 @@ function getManifestLayerType(manifest) {
78
81
  }
79
82
  throw new Error(`${manifest.mediaType} not recognized.`);
80
83
  }
81
- exports.getManifestLayerType = getManifestLayerType;
82
84
  function getLayerTypeFileEnding(layer) {
83
85
  switch (layer.mediaType) {
84
86
  case MIMETypes_1.OCI.layer.gzip:
@@ -91,15 +93,12 @@ function getLayerTypeFileEnding(layer) {
91
93
  throw new Error(`Layer mediaType ${layer.mediaType} not known.`);
92
94
  }
93
95
  }
94
- exports.getLayerTypeFileEnding = getLayerTypeFileEnding;
95
96
  function getHash(digest) {
96
97
  return digest.split(":")[1];
97
98
  }
98
- exports.getHash = getHash;
99
99
  function parseImage(imageStr) {
100
100
  const ar = imageStr.split(":");
101
101
  const tag = ar[1] || "latest";
102
102
  const ipath = ar[0];
103
103
  return { path: ipath, tag: tag };
104
104
  }
105
- exports.parseImage = parseImage;
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.1.0";
1
+ export declare const VERSION = "3.1.2";
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = "3.1.0";
4
+ exports.VERSION = "3.1.2";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "containerify",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Build node.js docker images without docker",
5
5
  "main": "./lib/cli.js",
6
6
  "scripts": {