iterate-skill-installer 3.10.0 → 3.11.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 +29 -3
- package/package.json +1 -1
package/lib/installer.js
CHANGED
|
@@ -166,6 +166,25 @@ const ITERATE_SIGNING_PUBLIC_KEY = [
|
|
|
166
166
|
'-----END PGP PUBLIC KEY BLOCK-----',
|
|
167
167
|
].join('\n');
|
|
168
168
|
|
|
169
|
+
//: SHA-1 fingerprint of the pinned signing key (uid jingzhao-l (sign-github)).
|
|
170
|
+
//: Verification is only accepted when the ``VALIDSIG`` fingerprint belongs to
|
|
171
|
+
//: this key, not merely on a GOODSIG/exit-0 — a substituted signer whose key
|
|
172
|
+
//: gpg auto-retrieved would otherwise pass. Keep in sync with
|
|
173
|
+
//: ``iterate_cli/signing.py`` and ``scripts/install.py``.
|
|
174
|
+
const ITERATE_SIGNING_KEY_FINGERPRINT = '0929EA31DF4F7429F63FC53189D88B1D043A1298';
|
|
175
|
+
|
|
176
|
+
//: Extract the fingerprints gpg reported as ``VALIDSIG`` in ``--status-fd``
|
|
177
|
+
//: output. A status line is ``[GNUPG:] VALIDSIG <fpr> <date> …``.
|
|
178
|
+
function validsigFingerprints(statusOutput) {
|
|
179
|
+
const fprs = [];
|
|
180
|
+
for (const line of String(statusOutput || '').split('\n')) {
|
|
181
|
+
if (!line.startsWith('[GNUPG:] VALIDSIG ')) continue;
|
|
182
|
+
const parts = line.split(/\s+/);
|
|
183
|
+
if (parts.length >= 3 && parts[2]) fprs.push(parts[2].toUpperCase());
|
|
184
|
+
}
|
|
185
|
+
return fprs;
|
|
186
|
+
}
|
|
187
|
+
|
|
169
188
|
const ITERATE_BANNER = [
|
|
170
189
|
'██╗████████╗███████╗██████╗ █████╗ ████████╗███████╗',
|
|
171
190
|
'██║╚══██╔══╝██╔════╝██╔══██╗██╔══██╗╚══██╔══╝██╔════╝',
|
|
@@ -616,7 +635,7 @@ function verifyGpgDetachedSignature(artifactPath, signaturePath, publicKeyArmor,
|
|
|
616
635
|
|
|
617
636
|
const verifyResult = spawnSync(
|
|
618
637
|
'gpg',
|
|
619
|
-
['--homedir', gpgHome, '--batch', '--quiet', '--no-autostart', '--verify', signaturePath, artifactPath],
|
|
638
|
+
['--homedir', gpgHome, '--batch', '--quiet', '--no-autostart', '--no-auto-key-retrieve', '--status-fd', '1', '--verify', signaturePath, artifactPath],
|
|
620
639
|
{ encoding: 'utf8', timeout, killSignal: 'SIGKILL' }
|
|
621
640
|
);
|
|
622
641
|
if (verifyResult.error) {
|
|
@@ -631,8 +650,15 @@ function verifyGpgDetachedSignature(artifactPath, signaturePath, publicKeyArmor,
|
|
|
631
650
|
}
|
|
632
651
|
return { status: 'unavailable', detail: `gpg launch failed: ${verifyResult.error.message}` };
|
|
633
652
|
}
|
|
634
|
-
//
|
|
635
|
-
|
|
653
|
+
// A GOODSIG (or exit 0) alone does not prove the signer is the pinned key: a
|
|
654
|
+
// substituted signer whose key gpg auto-retrieved would pass. Require a
|
|
655
|
+
// VALIDSIG fingerprint belonging to the pinned key, mirroring
|
|
656
|
+
// iterate_cli/signing.py and scripts/install.py (keep in sync).
|
|
657
|
+
const signerFingerprints = validsigFingerprints(verifyResult.stdout);
|
|
658
|
+
const matchesPinned = signerFingerprints.some(
|
|
659
|
+
(fpr) => fpr === ITERATE_SIGNING_KEY_FINGERPRINT
|
|
660
|
+
);
|
|
661
|
+
if (verifyResult.status === 0 && matchesPinned) {
|
|
636
662
|
return { status: 'verified', detail: (verifyResult.stderr || '').trim() };
|
|
637
663
|
}
|
|
638
664
|
return { status: 'invalid', detail: (verifyResult.stderr || '').trim() || `gpg exited ${verifyResult.status}` };
|