@4cloudguru/pipeline-task-ado 0.1.1 → 0.2.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/README.md CHANGED
@@ -42,7 +42,7 @@ Modules move here one family at a time, smallest first, so the migration pattern
42
42
  is proven on something harmless before anything security-bearing moves:
43
43
 
44
44
  - [x] `getBoolInputDefaultTrue` — fail-closed boolean input
45
- - [ ] `http-client` — proxy-aware, HTTPS-pinned client wiring over `-core`
45
+ - [x] `http-client` — proxy-aware, HTTPS-pinned client wiring over `-core`
46
46
  - [ ] `registry-version-resolver`
47
47
  - [ ] `https-client`
48
48
 
package/dist/index.cjs CHANGED
@@ -1,13 +1,40 @@
1
1
  'use strict';
2
2
 
3
3
  var task_js = require('azure-pipelines-task-lib/task.js');
4
+ var undici = require('undici');
5
+ var pipelineTaskCore = require('@4cloudguru/pipeline-task-core');
4
6
 
5
7
  // src/input/bool-input.ts
6
8
  function getBoolInputDefaultTrue(name) {
7
9
  const raw = task_js.getInput(name, false);
8
10
  return raw === void 0 || raw.trim() === "" ? true : raw.trim().toLowerCase() !== "false";
9
11
  }
12
+ function buildAdoFetchOptions() {
13
+ const resolved = pipelineTaskCore.resolveProxy(task_js.getHttpProxyConfiguration());
14
+ if (!resolved) return {};
15
+ for (const secret of resolved.secrets) {
16
+ task_js.setSecret(secret);
17
+ }
18
+ return {
19
+ // @ts-expect-error Node's fetch accepts an undici dispatcher at runtime.
20
+ dispatcher: new undici.ProxyAgent(resolved.proxyUrl)
21
+ };
22
+ }
23
+ function createAdoHttpClient(options) {
24
+ return pipelineTaskCore.createHttpClient({
25
+ // Re-evaluated per attempt, so a proxy change between retries is picked up.
26
+ fetchOptions: buildAdoFetchOptions,
27
+ // Passed by reference rather than wrapped: a forwarding lambda would be an
28
+ // extra function no test can meaningfully reach, and task-lib's debug does
29
+ // not close over `this`.
30
+ debug: task_js.debug,
31
+ messages: options.messages,
32
+ ...options.redirectPolicy ? { redirectPolicy: options.redirectPolicy } : {}
33
+ });
34
+ }
10
35
 
36
+ exports.buildAdoFetchOptions = buildAdoFetchOptions;
37
+ exports.createAdoHttpClient = createAdoHttpClient;
11
38
  exports.getBoolInputDefaultTrue = getBoolInputDefaultTrue;
12
39
  //# sourceMappingURL=index.cjs.map
13
40
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/input/bool-input.ts"],"names":["getInput"],"mappings":";;;;;AAYO,SAAS,wBAAwB,IAAA,EAAuB;AAC7D,EAAA,MAAM,GAAA,GAAMA,gBAAA,CAAS,IAAA,EAAM,KAAK,CAAA;AAChC,EAAA,OAAO,GAAA,KAAQ,MAAA,IAAa,GAAA,CAAI,IAAA,EAAK,KAAM,EAAA,GAAK,IAAA,GAAO,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,OAAA;AACtF","file":"index.cjs","sourcesContent":["// The `.js` extension is load-bearing: azure-pipelines-task-lib is CommonJS with\n// no `exports` map, so under ESM resolution the extensionless subpath does not\n// resolve at all (ERR_MODULE_NOT_FOUND). CJS is unaffected either way.\nimport { getInput } from 'azure-pipelines-task-lib/task.js'\n\n/**\n * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the\n * raw input rather than getBoolInput(name, false) so the default still holds on an\n * agent that does not materialize task.json defaultValues into the input env var\n * (where getBoolInput would silently return false): unset/empty -> true; any value\n * other than \"false\" (case-insensitive) -> true.\n */\nexport function getBoolInputDefaultTrue(name: string): boolean {\n const raw = getInput(name, false)\n return raw === undefined || raw.trim() === '' ? true : raw.trim().toLowerCase() !== 'false'\n}\n"]}
1
+ {"version":3,"sources":["../src/input/bool-input.ts","../src/http/ado-http.ts"],"names":["getInput","resolveProxy","getHttpProxyConfiguration","setSecret","ProxyAgent","createHttpClient","debug"],"mappings":";;;;;;;AAYO,SAAS,wBAAwB,IAAA,EAAuB;AAC7D,EAAA,MAAM,GAAA,GAAMA,gBAAA,CAAS,IAAA,EAAM,KAAK,CAAA;AAChC,EAAA,OAAO,GAAA,KAAQ,MAAA,IAAa,GAAA,CAAI,IAAA,EAAK,KAAM,EAAA,GAAK,IAAA,GAAO,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,OAAA;AACtF;ACOO,SAAS,oBAAA,GAAoC;AAClD,EAAA,MAAM,QAAA,GAAWC,6BAAA,CAAaC,iCAAA,EAA2B,CAAA;AACzD,EAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AAEvB,EAAA,KAAA,MAAW,MAAA,IAAU,SAAS,OAAA,EAAS;AACrC,IAAAC,iBAAA,CAAU,MAAM,CAAA;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA;AAAA,IAEL,UAAA,EAAY,IAAIC,iBAAA,CAAW,QAAA,CAAS,QAAQ;AAAA,GAC9C;AACF;AAmBO,SAAS,oBAAoB,OAAA,EAA2C;AAC7E,EAAA,OAAOC,iCAAA,CAAiB;AAAA;AAAA,IAEtB,YAAA,EAAc,oBAAA;AAAA;AAAA;AAAA;AAAA,WAIdC,aAAA;AAAA,IACA,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,GAAI,QAAQ,cAAA,GAAiB,EAAE,gBAAgB,OAAA,CAAQ,cAAA,KAAmB;AAAC,GAC5E,CAAA;AACH","file":"index.cjs","sourcesContent":["// The `.js` extension is load-bearing: azure-pipelines-task-lib is CommonJS with\n// no `exports` map, so under ESM resolution the extensionless subpath does not\n// resolve at all (ERR_MODULE_NOT_FOUND). CJS is unaffected either way.\nimport { getInput } from 'azure-pipelines-task-lib/task.js'\n\n/**\n * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the\n * raw input rather than getBoolInput(name, false) so the default still holds on an\n * agent that does not materialize task.json defaultValues into the input env var\n * (where getBoolInput would silently return false): unset/empty -> true; any value\n * other than \"false\" (case-insensitive) -> true.\n */\nexport function getBoolInputDefaultTrue(name: string): boolean {\n const raw = getInput(name, false)\n return raw === undefined || raw.trim() === '' ? true : raw.trim().toLowerCase() !== 'false'\n}\n","import { debug, getHttpProxyConfiguration, setSecret } from 'azure-pipelines-task-lib/task.js'\nimport { ProxyAgent } from 'undici'\nimport {\n createHttpClient,\n resolveProxy,\n type HttpClient,\n type HttpMessages,\n type RedirectPolicy,\n} from '@4cloudguru/pipeline-task-core'\n\n/**\n * Per-attempt fetch init carrying the agent's proxy.\n *\n * The ordering is the security property, not an implementation detail: the\n * agent's masker matches registered literals rather than derivations of them,\n * and resolveProxy returns every spelling of the credential it produced —\n * including the percent-encoded form the dispatcher URL actually embeds, and\n * any userinfo already inside Agent.ProxyUrl. All of them must be registered\n * BEFORE proxyUrl is handed to a dispatcher or interpolated into a message.\n * resolveProxy cannot do it itself; the package it lives in does not import\n * the task lib. That obligation is the reason this function exists here.\n */\nexport function buildAdoFetchOptions(): RequestInit {\n const resolved = resolveProxy(getHttpProxyConfiguration())\n if (!resolved) return {}\n\n for (const secret of resolved.secrets) {\n setSecret(secret)\n }\n\n return {\n // @ts-expect-error Node's fetch accepts an undici dispatcher at runtime.\n dispatcher: new ProxyAgent(resolved.proxyUrl),\n }\n}\n\nexport interface AdoHttpClientOptions {\n /**\n * Failure text. Kept a parameter because it is the one genuinely per-task\n * part: the strings come from each task's own resource file via tasks.loc,\n * and \"registry request failed\" is wrong on a releases.hashicorp.com fetch.\n */\n messages: HttpMessages\n /**\n * Defaults to the core client's own same-host rule. Pass\n * anyRedirectPolicy(sameHostOnly, githubAssetRedirects) only for callers that\n * really do fetch GitHub release assets — enabling it estate-wide widens the\n * redirect surface for callers that never need it.\n */\n redirectPolicy?: RedirectPolicy\n}\n\n/** An HTTPS-pinned client wired to this agent's proxy, debug channel and text. */\nexport function createAdoHttpClient(options: AdoHttpClientOptions): HttpClient {\n return createHttpClient({\n // Re-evaluated per attempt, so a proxy change between retries is picked up.\n fetchOptions: buildAdoFetchOptions,\n // Passed by reference rather than wrapped: a forwarding lambda would be an\n // extra function no test can meaningfully reach, and task-lib's debug does\n // not close over `this`.\n debug,\n messages: options.messages,\n ...(options.redirectPolicy ? { redirectPolicy: options.redirectPolicy } : {}),\n })\n}\n"]}
package/dist/index.d.mts CHANGED
@@ -1,3 +1,5 @@
1
+ import { HttpMessages, RedirectPolicy, HttpClient } from '@4cloudguru/pipeline-task-core';
2
+
1
3
  /**
2
4
  * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the
3
5
  * raw input rather than getBoolInput(name, false) so the default still holds on an
@@ -7,4 +9,35 @@
7
9
  */
8
10
  declare function getBoolInputDefaultTrue(name: string): boolean;
9
11
 
10
- export { getBoolInputDefaultTrue };
12
+ /**
13
+ * Per-attempt fetch init carrying the agent's proxy.
14
+ *
15
+ * The ordering is the security property, not an implementation detail: the
16
+ * agent's masker matches registered literals rather than derivations of them,
17
+ * and resolveProxy returns every spelling of the credential it produced —
18
+ * including the percent-encoded form the dispatcher URL actually embeds, and
19
+ * any userinfo already inside Agent.ProxyUrl. All of them must be registered
20
+ * BEFORE proxyUrl is handed to a dispatcher or interpolated into a message.
21
+ * resolveProxy cannot do it itself; the package it lives in does not import
22
+ * the task lib. That obligation is the reason this function exists here.
23
+ */
24
+ declare function buildAdoFetchOptions(): RequestInit;
25
+ interface AdoHttpClientOptions {
26
+ /**
27
+ * Failure text. Kept a parameter because it is the one genuinely per-task
28
+ * part: the strings come from each task's own resource file via tasks.loc,
29
+ * and "registry request failed" is wrong on a releases.hashicorp.com fetch.
30
+ */
31
+ messages: HttpMessages;
32
+ /**
33
+ * Defaults to the core client's own same-host rule. Pass
34
+ * anyRedirectPolicy(sameHostOnly, githubAssetRedirects) only for callers that
35
+ * really do fetch GitHub release assets — enabling it estate-wide widens the
36
+ * redirect surface for callers that never need it.
37
+ */
38
+ redirectPolicy?: RedirectPolicy;
39
+ }
40
+ /** An HTTPS-pinned client wired to this agent's proxy, debug channel and text. */
41
+ declare function createAdoHttpClient(options: AdoHttpClientOptions): HttpClient;
42
+
43
+ export { type AdoHttpClientOptions, buildAdoFetchOptions, createAdoHttpClient, getBoolInputDefaultTrue };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { HttpMessages, RedirectPolicy, HttpClient } from '@4cloudguru/pipeline-task-core';
2
+
1
3
  /**
2
4
  * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the
3
5
  * raw input rather than getBoolInput(name, false) so the default still holds on an
@@ -7,4 +9,35 @@
7
9
  */
8
10
  declare function getBoolInputDefaultTrue(name: string): boolean;
9
11
 
10
- export { getBoolInputDefaultTrue };
12
+ /**
13
+ * Per-attempt fetch init carrying the agent's proxy.
14
+ *
15
+ * The ordering is the security property, not an implementation detail: the
16
+ * agent's masker matches registered literals rather than derivations of them,
17
+ * and resolveProxy returns every spelling of the credential it produced —
18
+ * including the percent-encoded form the dispatcher URL actually embeds, and
19
+ * any userinfo already inside Agent.ProxyUrl. All of them must be registered
20
+ * BEFORE proxyUrl is handed to a dispatcher or interpolated into a message.
21
+ * resolveProxy cannot do it itself; the package it lives in does not import
22
+ * the task lib. That obligation is the reason this function exists here.
23
+ */
24
+ declare function buildAdoFetchOptions(): RequestInit;
25
+ interface AdoHttpClientOptions {
26
+ /**
27
+ * Failure text. Kept a parameter because it is the one genuinely per-task
28
+ * part: the strings come from each task's own resource file via tasks.loc,
29
+ * and "registry request failed" is wrong on a releases.hashicorp.com fetch.
30
+ */
31
+ messages: HttpMessages;
32
+ /**
33
+ * Defaults to the core client's own same-host rule. Pass
34
+ * anyRedirectPolicy(sameHostOnly, githubAssetRedirects) only for callers that
35
+ * really do fetch GitHub release assets — enabling it estate-wide widens the
36
+ * redirect surface for callers that never need it.
37
+ */
38
+ redirectPolicy?: RedirectPolicy;
39
+ }
40
+ /** An HTTPS-pinned client wired to this agent's proxy, debug channel and text. */
41
+ declare function createAdoHttpClient(options: AdoHttpClientOptions): HttpClient;
42
+
43
+ export { type AdoHttpClientOptions, buildAdoFetchOptions, createAdoHttpClient, getBoolInputDefaultTrue };
package/dist/index.js CHANGED
@@ -1,11 +1,36 @@
1
- import { getInput } from 'azure-pipelines-task-lib/task.js';
1
+ import { getInput, getHttpProxyConfiguration, setSecret, debug } from 'azure-pipelines-task-lib/task.js';
2
+ import { ProxyAgent } from 'undici';
3
+ import { resolveProxy, createHttpClient } from '@4cloudguru/pipeline-task-core';
2
4
 
3
5
  // src/input/bool-input.ts
4
6
  function getBoolInputDefaultTrue(name) {
5
7
  const raw = getInput(name, false);
6
8
  return raw === void 0 || raw.trim() === "" ? true : raw.trim().toLowerCase() !== "false";
7
9
  }
10
+ function buildAdoFetchOptions() {
11
+ const resolved = resolveProxy(getHttpProxyConfiguration());
12
+ if (!resolved) return {};
13
+ for (const secret of resolved.secrets) {
14
+ setSecret(secret);
15
+ }
16
+ return {
17
+ // @ts-expect-error Node's fetch accepts an undici dispatcher at runtime.
18
+ dispatcher: new ProxyAgent(resolved.proxyUrl)
19
+ };
20
+ }
21
+ function createAdoHttpClient(options) {
22
+ return createHttpClient({
23
+ // Re-evaluated per attempt, so a proxy change between retries is picked up.
24
+ fetchOptions: buildAdoFetchOptions,
25
+ // Passed by reference rather than wrapped: a forwarding lambda would be an
26
+ // extra function no test can meaningfully reach, and task-lib's debug does
27
+ // not close over `this`.
28
+ debug,
29
+ messages: options.messages,
30
+ ...options.redirectPolicy ? { redirectPolicy: options.redirectPolicy } : {}
31
+ });
32
+ }
8
33
 
9
- export { getBoolInputDefaultTrue };
34
+ export { buildAdoFetchOptions, createAdoHttpClient, getBoolInputDefaultTrue };
10
35
  //# sourceMappingURL=index.js.map
11
36
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/input/bool-input.ts"],"names":[],"mappings":";;;AAYO,SAAS,wBAAwB,IAAA,EAAuB;AAC7D,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,EAAM,KAAK,CAAA;AAChC,EAAA,OAAO,GAAA,KAAQ,MAAA,IAAa,GAAA,CAAI,IAAA,EAAK,KAAM,EAAA,GAAK,IAAA,GAAO,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,OAAA;AACtF","file":"index.js","sourcesContent":["// The `.js` extension is load-bearing: azure-pipelines-task-lib is CommonJS with\n// no `exports` map, so under ESM resolution the extensionless subpath does not\n// resolve at all (ERR_MODULE_NOT_FOUND). CJS is unaffected either way.\nimport { getInput } from 'azure-pipelines-task-lib/task.js'\n\n/**\n * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the\n * raw input rather than getBoolInput(name, false) so the default still holds on an\n * agent that does not materialize task.json defaultValues into the input env var\n * (where getBoolInput would silently return false): unset/empty -> true; any value\n * other than \"false\" (case-insensitive) -> true.\n */\nexport function getBoolInputDefaultTrue(name: string): boolean {\n const raw = getInput(name, false)\n return raw === undefined || raw.trim() === '' ? true : raw.trim().toLowerCase() !== 'false'\n}\n"]}
1
+ {"version":3,"sources":["../src/input/bool-input.ts","../src/http/ado-http.ts"],"names":[],"mappings":";;;;;AAYO,SAAS,wBAAwB,IAAA,EAAuB;AAC7D,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,IAAA,EAAM,KAAK,CAAA;AAChC,EAAA,OAAO,GAAA,KAAQ,MAAA,IAAa,GAAA,CAAI,IAAA,EAAK,KAAM,EAAA,GAAK,IAAA,GAAO,GAAA,CAAI,IAAA,EAAK,CAAE,WAAA,EAAY,KAAM,OAAA;AACtF;ACOO,SAAS,oBAAA,GAAoC;AAClD,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,yBAAA,EAA2B,CAAA;AACzD,EAAA,IAAI,CAAC,QAAA,EAAU,OAAO,EAAC;AAEvB,EAAA,KAAA,MAAW,MAAA,IAAU,SAAS,OAAA,EAAS;AACrC,IAAA,SAAA,CAAU,MAAM,CAAA;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA;AAAA,IAEL,UAAA,EAAY,IAAI,UAAA,CAAW,QAAA,CAAS,QAAQ;AAAA,GAC9C;AACF;AAmBO,SAAS,oBAAoB,OAAA,EAA2C;AAC7E,EAAA,OAAO,gBAAA,CAAiB;AAAA;AAAA,IAEtB,YAAA,EAAc,oBAAA;AAAA;AAAA;AAAA;AAAA,IAId,KAAA;AAAA,IACA,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,GAAI,QAAQ,cAAA,GAAiB,EAAE,gBAAgB,OAAA,CAAQ,cAAA,KAAmB;AAAC,GAC5E,CAAA;AACH","file":"index.js","sourcesContent":["// The `.js` extension is load-bearing: azure-pipelines-task-lib is CommonJS with\n// no `exports` map, so under ESM resolution the extensionless subpath does not\n// resolve at all (ERR_MODULE_NOT_FOUND). CJS is unaffected either way.\nimport { getInput } from 'azure-pipelines-task-lib/task.js'\n\n/**\n * Reads a boolean input whose intended default is TRUE (fail-closed). It reads the\n * raw input rather than getBoolInput(name, false) so the default still holds on an\n * agent that does not materialize task.json defaultValues into the input env var\n * (where getBoolInput would silently return false): unset/empty -> true; any value\n * other than \"false\" (case-insensitive) -> true.\n */\nexport function getBoolInputDefaultTrue(name: string): boolean {\n const raw = getInput(name, false)\n return raw === undefined || raw.trim() === '' ? true : raw.trim().toLowerCase() !== 'false'\n}\n","import { debug, getHttpProxyConfiguration, setSecret } from 'azure-pipelines-task-lib/task.js'\nimport { ProxyAgent } from 'undici'\nimport {\n createHttpClient,\n resolveProxy,\n type HttpClient,\n type HttpMessages,\n type RedirectPolicy,\n} from '@4cloudguru/pipeline-task-core'\n\n/**\n * Per-attempt fetch init carrying the agent's proxy.\n *\n * The ordering is the security property, not an implementation detail: the\n * agent's masker matches registered literals rather than derivations of them,\n * and resolveProxy returns every spelling of the credential it produced —\n * including the percent-encoded form the dispatcher URL actually embeds, and\n * any userinfo already inside Agent.ProxyUrl. All of them must be registered\n * BEFORE proxyUrl is handed to a dispatcher or interpolated into a message.\n * resolveProxy cannot do it itself; the package it lives in does not import\n * the task lib. That obligation is the reason this function exists here.\n */\nexport function buildAdoFetchOptions(): RequestInit {\n const resolved = resolveProxy(getHttpProxyConfiguration())\n if (!resolved) return {}\n\n for (const secret of resolved.secrets) {\n setSecret(secret)\n }\n\n return {\n // @ts-expect-error Node's fetch accepts an undici dispatcher at runtime.\n dispatcher: new ProxyAgent(resolved.proxyUrl),\n }\n}\n\nexport interface AdoHttpClientOptions {\n /**\n * Failure text. Kept a parameter because it is the one genuinely per-task\n * part: the strings come from each task's own resource file via tasks.loc,\n * and \"registry request failed\" is wrong on a releases.hashicorp.com fetch.\n */\n messages: HttpMessages\n /**\n * Defaults to the core client's own same-host rule. Pass\n * anyRedirectPolicy(sameHostOnly, githubAssetRedirects) only for callers that\n * really do fetch GitHub release assets — enabling it estate-wide widens the\n * redirect surface for callers that never need it.\n */\n redirectPolicy?: RedirectPolicy\n}\n\n/** An HTTPS-pinned client wired to this agent's proxy, debug channel and text. */\nexport function createAdoHttpClient(options: AdoHttpClientOptions): HttpClient {\n return createHttpClient({\n // Re-evaluated per attempt, so a proxy change between retries is picked up.\n fetchOptions: buildAdoFetchOptions,\n // Passed by reference rather than wrapped: a forwarding lambda would be an\n // extra function no test can meaningfully reach, and task-lib's debug does\n // not close over `this`.\n debug,\n messages: options.messages,\n ...(options.redirectPolicy ? { redirectPolicy: options.redirectPolicy } : {}),\n })\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@4cloudguru/pipeline-task-ado",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Azure DevOps-specific task primitives shared by the Azure Pipelines task extensions.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,
@@ -69,7 +69,7 @@
69
69
  "prettier": "3.9.6",
70
70
  "tsup": "^8.3.5",
71
71
  "typescript": "^5.9.3",
72
- "undici": "^7.16.0",
72
+ "undici": "^8.10.0",
73
73
  "vitest": "^4.1.7"
74
74
  }
75
75
  }