iterate-skill-installer 3.2.3 → 3.3.1
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/lib/installer.js +38 -10
- package/package.json +1 -1
package/lib/installer.js
CHANGED
|
@@ -193,14 +193,43 @@ function isGithubApiUrl(url) {
|
|
|
193
193
|
return hostname === 'api.github.com' || hostname.endsWith('.api.github.com');
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Normalize a caller-supplied GitHub token.
|
|
198
|
+
*
|
|
199
|
+
* Tokens frequently arrive with surrounding whitespace (a trailing newline
|
|
200
|
+
* from `export GITHUB_TOKEN=$(cat secret)` or a shell alias that echoes the
|
|
201
|
+
* value); an untrimmed token makes every authenticated call fail with 401
|
|
202
|
+
* while silently burning the user's GitHub API rate limit. An empty result is
|
|
203
|
+
* treated as "no token".
|
|
204
|
+
*/
|
|
205
|
+
function normalizeToken(raw) {
|
|
206
|
+
if (raw == null) return null;
|
|
207
|
+
const trimmed = String(raw).trim();
|
|
208
|
+
return trimmed === '' ? null : trimmed;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Compose the curl flags that attach the caller's PAT — and only those. The
|
|
213
|
+
* token is never attached to a non-API host; and marking it up differently
|
|
214
|
+
* from install.py would let the two installers disagree about credentials.
|
|
215
|
+
*
|
|
216
|
+
* Critically, a custom `-H "Authorization: Bearer ..."` header is echoed by
|
|
217
|
+
* curl onto EVERY host in a `-L` redirect chain (unlike `--user`, curl has no
|
|
218
|
+
* notion of stripping auth on a host change for raw headers). When the token
|
|
219
|
+
* is attached we therefore forbid redirects outright: a redirect then fails
|
|
220
|
+
* loudly instead of leaking the PAT to a foreign host.
|
|
221
|
+
*/
|
|
222
|
+
function buildAuthFlags(url, token) {
|
|
223
|
+
if (!token) return [];
|
|
224
|
+
if (!isGithubApiUrl(url)) return [];
|
|
225
|
+
return ['-H', `Authorization: Bearer ${token}`, '--max-redirs', '0'];
|
|
226
|
+
}
|
|
227
|
+
|
|
196
228
|
async function fetchJson(url, token) {
|
|
197
229
|
// Prefer curl over Node.js fetch because curl uses the system CA store
|
|
198
230
|
// and avoids Node-specific certificate issues in some environments.
|
|
199
231
|
const failFlag = (await supportsCurlFailWithBody()) ? '--fail-with-body' : '--fail';
|
|
200
|
-
const args = ['-sSL', failFlag, '--max-time', CURL_MAX_TIME_SECONDS, '--max-filesize', String(JSON_MAX_BYTES), '-H', 'Accept: application/vnd.github+json', '-H', 'X-GitHub-Api-Version: 2022-11-28', '-H', 'User-Agent: iterate-skill-installer'];
|
|
201
|
-
if (token && isGithubApiUrl(url)) {
|
|
202
|
-
args.push('-H', `Authorization: Bearer ${token}`);
|
|
203
|
-
}
|
|
232
|
+
const args = ['-sSL', failFlag, '--max-time', CURL_MAX_TIME_SECONDS, '--max-filesize', String(JSON_MAX_BYTES), '-H', 'Accept: application/vnd.github+json', '-H', 'X-GitHub-Api-Version: 2022-11-28', '-H', 'User-Agent: iterate-skill-installer', ...buildAuthFlags(url, token)];
|
|
204
233
|
args.push(url);
|
|
205
234
|
const stdout = await runCommand('curl', args);
|
|
206
235
|
try {
|
|
@@ -224,11 +253,8 @@ async function fetchJson(url, token) {
|
|
|
224
253
|
*/
|
|
225
254
|
async function downloadFile(url, destPath, token, { progress = false, maxBytes = TARBALL_MAX_BYTES } = {}) {
|
|
226
255
|
const failFlag = (await supportsCurlFailWithBody()) ? '--fail-with-body' : '--fail';
|
|
227
|
-
const args = ['-sSL', failFlag, '--max-time', CURL_MAX_TIME_SECONDS, '--max-filesize', String(maxBytes), '-o', destPath, '-H', 'User-Agent: iterate-skill-installer'];
|
|
256
|
+
const args = ['-sSL', failFlag, '--max-time', CURL_MAX_TIME_SECONDS, '--max-filesize', String(maxBytes), '-o', destPath, '-H', 'User-Agent: iterate-skill-installer', ...buildAuthFlags(url, token)];
|
|
228
257
|
if (progress) args.push('--progress-bar');
|
|
229
|
-
if (token && isGithubApiUrl(url)) {
|
|
230
|
-
args.push('-H', `Authorization: Bearer ${token}`);
|
|
231
|
-
}
|
|
232
258
|
args.push(url);
|
|
233
259
|
if (progress) {
|
|
234
260
|
// Let curl write its progress bar directly to the terminal.
|
|
@@ -591,7 +617,7 @@ function parseArgs(argv) {
|
|
|
591
617
|
target: null,
|
|
592
618
|
force: false,
|
|
593
619
|
noCli: false,
|
|
594
|
-
token: process.env.GITHUB_TOKEN
|
|
620
|
+
token: normalizeToken(process.env.GITHUB_TOKEN),
|
|
595
621
|
// Non-install action requested via -h/--help/-v/--version. bin/cli.js
|
|
596
622
|
// inspects this before running main() and exits 0 without installing.
|
|
597
623
|
mode: null,
|
|
@@ -660,7 +686,7 @@ function parseArgs(argv) {
|
|
|
660
686
|
console.error('Error: --token requires a value (a flag was found instead)');
|
|
661
687
|
process.exit(1);
|
|
662
688
|
}
|
|
663
|
-
options.token = next;
|
|
689
|
+
options.token = normalizeToken(next);
|
|
664
690
|
i++;
|
|
665
691
|
break;
|
|
666
692
|
default:
|
|
@@ -860,5 +886,7 @@ module.exports = {
|
|
|
860
886
|
extractTarball,
|
|
861
887
|
rejectLinkEntries,
|
|
862
888
|
isGithubApiUrl,
|
|
889
|
+
normalizeToken,
|
|
890
|
+
buildAuthFlags,
|
|
863
891
|
supportsCurlFailWithBody,
|
|
864
892
|
};
|