glasspane-install 1.8.2 → 1.10.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/cli.js +49 -9
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -69,7 +69,7 @@ export const INSTALL_SH_URL =
|
|
|
69
69
|
/** 发布线锚点(版本真源 = 根 package.json,由 scripts/set-version.mjs 统一改写,
|
|
70
70
|
* 勿手改):npx 形态下本地没有仓库时,引导 clone 的就是这个 tag,与 install.sh
|
|
71
71
|
* 的 `GLASSPANE_RELEASE` 同值——两条一键入口必须拿到同一份源码。 */
|
|
72
|
-
export const RELEASE_VERSION = '1.
|
|
72
|
+
export const RELEASE_VERSION = '1.10.0'
|
|
73
73
|
/** 发布 ref(tag 名)。GLASSPANE_REF 环境变量可覆盖(追主干用 `main`)。 */
|
|
74
74
|
export const REPO_REF = `v${RELEASE_VERSION}`
|
|
75
75
|
|
|
@@ -762,6 +762,50 @@ export function classifyTagVerify({ status, stdout = '', stderr = '' } = {}) {
|
|
|
762
762
|
return { status: 'invalid', detail: `git verify-tag 失败(退出码 ${status}),签名无法确证` }
|
|
763
763
|
}
|
|
764
764
|
|
|
765
|
+
/**
|
|
766
|
+
* 验签结论怎么落成安装动作。三种结局各说各话:
|
|
767
|
+
* - `verified` 绿字继续;
|
|
768
|
+
* - `unsigned` / `unavailable` 黄字继续——缺的是来源证明的**增量**:被验的 tag 与
|
|
769
|
+
* 装进构建的源码是同一个 ref,HTTPS + tag 钉版本已经保证内容完整;
|
|
770
|
+
* - `invalid` 签名在、验不过,那说的不是"缺证明"而是"这份字节不是发布者签过的
|
|
771
|
+
* 那一份",必须**停下**。自动更新那一面对它是硬拒且 `--consent` 洗不掉
|
|
772
|
+
* (updater/lib/check.js 的门 8);安装这一面从前只黄字一句"继续安装"就往下跑
|
|
773
|
+
* npm install、swift build 并注册 launchd——同一件事在两条路上按两种诚实度处理,
|
|
774
|
+
* 而安装是更不可逆的那条。
|
|
775
|
+
* 判据放在纯函数里:这一段从前埋在 main() 的 if 里,没有一条测试能指到它。
|
|
776
|
+
*/
|
|
777
|
+
export function tagVerifyDecision({ sig, pinRef, repoDir }) {
|
|
778
|
+
if (sig.status === 'verified') {
|
|
779
|
+
return { action: 'pass', text: `发布 tag ${pinRef} GPG 签名验证通过` }
|
|
780
|
+
}
|
|
781
|
+
if (sig.status === 'invalid') {
|
|
782
|
+
return {
|
|
783
|
+
action: 'refuse',
|
|
784
|
+
text: `发布 tag ${pinRef} 带着 GPG 签名,但签名验不过:${sig.detail}\n`
|
|
785
|
+
+ '这不是"没签名"。签名在而校验失败,说明眼前这份 tag 指向的字节不是发布者签过的那一份。'
|
|
786
|
+
+ '安装到此为止:没有跑 npm install,没有 swift build,没有注册 launchd 作业。\n'
|
|
787
|
+
+ `下一步:核对远端与这个 tag(git -C "${repoDir}" remote -v;git -C "${repoDir}" tag -v ${pinRef});`
|
|
788
|
+
+ '确认仓库与发布者公钥都无误后改用更新的发布 tag(GLASSPANE_REF=v<版本> 重跑)。'
|
|
789
|
+
+ '要装开发主线用 GLASSPANE_REF=main(那条路不做 tag 验签,会如实告警)。',
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
if (sig.status === 'unsigned' || sig.status === 'unavailable') {
|
|
793
|
+
return {
|
|
794
|
+
action: 'warn',
|
|
795
|
+
text: `发布 tag ${pinRef} 没有可核验的 GPG 签名(${sig.status}:${sig.detail})`
|
|
796
|
+
+ '——继续安装:缺的是来源证明的增量,不是篡改迹象',
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
// 没见过的新判据一律停下:把"不认识"当成"没签名"放过,等于每加一种失败模式
|
|
800
|
+
// 就自动退回成"继续安装"。
|
|
801
|
+
return {
|
|
802
|
+
action: 'refuse',
|
|
803
|
+
text: `发布 tag ${pinRef} 的验签回了一个安装器不认识的判据(${sig.status}:${sig.detail})。`
|
|
804
|
+
+ '安装到此为止:不认识的判据不许当成"没签名"放过。\n'
|
|
805
|
+
+ `下一步:手动核对(git -C "${repoDir}" tag -v ${pinRef}),确认无误后重新安装。`,
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
765
809
|
/** 仓库里是否存在指定 tag ref(IO 探测,纯判定)。 */
|
|
766
810
|
export function repoHasRef(repoDir, ref, { spawn = spawnSync } = {}) {
|
|
767
811
|
return spawn('git', ['-C', repoDir, 'rev-parse', '--verify', `refs/tags/${ref}`], { stdio: 'ignore' }).status === 0
|
|
@@ -1526,17 +1570,13 @@ export async function install({ options = parseArgs([]).options, env = process.e
|
|
|
1526
1570
|
rootDir = plan.targetDir
|
|
1527
1571
|
}
|
|
1528
1572
|
|
|
1529
|
-
// 发布 tag GPG
|
|
1530
|
-
// 公钥验签其签名。未签名/不可用只告警不阻断——HTTPS clone + tag 钉版本已保证内容
|
|
1531
|
-
// 完整性,GPG 是来源证明的增量(见 verifyCloneTagGpg)。
|
|
1573
|
+
// 发布 tag GPG 验签:动作怎么落由 `tagVerifyDecision` 判(纯函数,有单测)。
|
|
1532
1574
|
const pinRef = env.GLASSPANE_REF || REPO_REF
|
|
1533
1575
|
if (pinRef !== 'main' && repoHasRef(rootDir, pinRef)) {
|
|
1534
1576
|
const sig = verifyCloneTagGpg({ repoDir: rootDir, ref: pinRef })
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
printStep(paint(`发布 tag ${pinRef} 未通过 GPG 验签(${sig.status}:${sig.detail})——继续安装`, 'yellow'))
|
|
1539
|
-
}
|
|
1577
|
+
const verdict = tagVerifyDecision({ sig, pinRef, repoDir: rootDir })
|
|
1578
|
+
if (verdict.action === 'refuse') throw new Error(verdict.text)
|
|
1579
|
+
printStep(paint(verdict.text, verdict.action === 'pass' ? 'green' : 'yellow'))
|
|
1540
1580
|
}
|
|
1541
1581
|
|
|
1542
1582
|
const engineDir = path.join(rootDir, 'engine')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glasspane-install",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "GlassPane one-command installer: terminal onboarding → install deps → build TS + Swift engine → start daemon → open settings GUI for permission guide",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|