iterate-skill-installer 3.2.3 → 3.3.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/lib/installer.js +38 -9
- 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.
|
|
@@ -592,6 +618,7 @@ function parseArgs(argv) {
|
|
|
592
618
|
force: false,
|
|
593
619
|
noCli: false,
|
|
594
620
|
token: process.env.GITHUB_TOKEN || null,
|
|
621
|
+
token: normalizeToken(process.env.GITHUB_TOKEN),
|
|
595
622
|
// Non-install action requested via -h/--help/-v/--version. bin/cli.js
|
|
596
623
|
// inspects this before running main() and exits 0 without installing.
|
|
597
624
|
mode: null,
|
|
@@ -660,7 +687,7 @@ function parseArgs(argv) {
|
|
|
660
687
|
console.error('Error: --token requires a value (a flag was found instead)');
|
|
661
688
|
process.exit(1);
|
|
662
689
|
}
|
|
663
|
-
options.token = next;
|
|
690
|
+
options.token = normalizeToken(next);
|
|
664
691
|
i++;
|
|
665
692
|
break;
|
|
666
693
|
default:
|
|
@@ -860,5 +887,7 @@ module.exports = {
|
|
|
860
887
|
extractTarball,
|
|
861
888
|
rejectLinkEntries,
|
|
862
889
|
isGithubApiUrl,
|
|
890
|
+
normalizeToken,
|
|
891
|
+
buildAuthFlags,
|
|
863
892
|
supportsCurlFailWithBody,
|
|
864
893
|
};
|