From 94237b8e7da37f6242fa115aaf60fef0a88392c2 Mon Sep 17 00:00:00 2001 From: xuans Date: Sun, 27 Sep 2026 18:29:26 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=BA=90=E7=A0=81=E6=8D=A2?= =?UTF-8?q?=E8=A1=8C=E5=B9=B6=E9=AA=8C=E8=AF=81=E8=B7=A8=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AD=BE=E5=87=BA=E4=B8=80=E8=87=B4=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitattributes | 1 + .../releasearchive/source_boundary_test.go | 60 +++++++++++++++++++ build/README.md | 2 + doc/构建版本与数据库支持矩阵.md | 1 + 4 files changed, 64 insertions(+) diff --git a/.gitattributes b/.gitattributes index b20bde1..79fbd57 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ +* text=auto eol=lf *.sh text eol=lf *.service text eol=lf diff --git a/backend/internal/releasearchive/source_boundary_test.go b/backend/internal/releasearchive/source_boundary_test.go index 49026d7..bc2cdcf 100644 --- a/backend/internal/releasearchive/source_boundary_test.go +++ b/backend/internal/releasearchive/source_boundary_test.go @@ -81,6 +81,66 @@ func TestRepositoryIgnoreBoundaries(t *testing.T) { } } +func TestRepositoryCheckoutLineEndings(t *testing.T) { + root, sandbox := repositoryIgnoreFixture(t) + attributes, err := os.ReadFile(filepath.Join(root, ".gitattributes")) + if err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(sandbox, ".gitattributes"), attributes, 0o600); err != nil { + t.Fatal(err) + } + text := []byte("first line\nsecond line\n") + files := map[string][]byte{ + "backend/go.mod": text, + "backend/go.sum": text, + "frontend/package.json": text, + "frontend/package-lock.json": text, + "frontend/.npmrc": text, + "frontend/index.html": text, + "frontend/src/App.vue": text, + "frontend/src/App.js": text, + "frontend/src/App.css": text, + "build/toolchain.mjs": text, + "build/build-release.ps1": text, + "frontend/logo/fixture.png": {0x89, 0, 13, 10, 0xff}, + } + arguments := []string{"add", "--", ".gitattributes"} + for path, data := range files { + fullPath := filepath.Join(sandbox, filepath.FromSlash(path)) + if err := os.MkdirAll(filepath.Dir(fullPath), 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(fullPath, data, 0o600); err != nil { + t.Fatal(err) + } + arguments = append(arguments, path) + } + if output, err := repositoryGitCommand(sandbox, arguments...).CombinedOutput(); err != nil { + t.Fatalf("准备换行测试索引失败:%v\n%s", err, output) + } + // 从相同索引实际签出,证明用户换行设置不会改变文本,也不会转换二进制。 + for _, value := range []string{"true", "false", "input"} { + t.Run(value, func(t *testing.T) { + destination := t.TempDir() + command := repositoryGitCommand(sandbox, "-c", "core.autocrlf="+value, + "checkout-index", "--all", "--prefix="+filepath.ToSlash(destination)+"/") + if output, err := command.CombinedOutput(); err != nil { + t.Fatalf("签出换行测试源码失败:%v\n%s", err, output) + } + for path, expected := range files { + actual, err := os.ReadFile(filepath.Join(destination, filepath.FromSlash(path))) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(actual, expected) { + t.Errorf("签出改变了构建输入或二进制内容:%s", path) + } + } + }) + } +} + func repositoryIgnoreFixture(t *testing.T) (string, string) { t.Helper() if _, err := exec.LookPath("git"); err != nil { diff --git a/build/README.md b/build/README.md index c51d552..16611fd 100644 --- a/build/README.md +++ b/build/README.md @@ -73,6 +73,8 @@ powershell -ExecutionPolicy Bypass -File .\build\build-release.ps1 -OutputDirect 从 `npm test` 等父进程启动检查器时,npm 可能将用户级 `allow-scripts` 导出到环境变量,而项目级安装拒绝这种传递。本入口仅从子进程环境移除该白名单变量,不改用户配置;`--ignore-scripts` 仍强制生效。正式测试覆盖嵌套调用和主动尝试放行脚本的环境设置,不能通过开启安装脚本解决此兼容问题。 +仓库 `.gitattributes` 对自动识别的文本固定 LF,避免不同 `core.autocrlf` 设置改变 Vue/CSS/HTML 构建输入及产物哈希,二进制保持原样。已有工作目录不会因此被强制重写;正式验证从干净克隆执行,不用脚本批量替换中文文件或清理既有数据。正式 Go 测试实际签出三种换行设置并检查文本和二进制字节。归档生成时间和源码提交信息仍可能影响包字节,因此不能把前端文件一致等同于所有归档逐字节一致。 + ## 本机路径保护 正式服务端和辅助程序统一使用 `-trimpath`。手动构建也必须保留此参数,例如 `go build -trimpath -o scert ./cmd/scert`。前端生产构建明确关闭源码映射。 diff --git a/doc/构建版本与数据库支持矩阵.md b/doc/构建版本与数据库支持矩阵.md index 63d4870..694c36f 100644 --- a/doc/构建版本与数据库支持矩阵.md +++ b/doc/构建版本与数据库支持矩阵.md @@ -47,6 +47,7 @@ npm.cmd run build | 安装脚本 | `.npmrc` 固定 `ignore-scripts=true`,正式入口再显式传参 | npm 未审查警告不是安全保证,禁止白名单和全量放行 | | 可选平台包 | `npm ci` 显式包含开发和可选依赖 | esbuild 不执行安装脚本,使用锁文件中的平台包;外部二进制覆盖被拒绝 | | 发布追溯 | `manifest.json` 的 `build_environment` | 包含实际工具链、系统、直接前端依赖、安装策略和五份输入文件 SHA256;Go 驱动及依赖由模块文件哈希追溯 | +| 源码换行 | `.gitattributes` 固定文本 LF,二进制自动识别并保留 | 覆盖用户 `core.autocrlf` 差异;原目录不强制重写,正式验证使用干净克隆 | 正式发布入口自动校验工具链、核验 Go 模块缓存、按锁文件干净安装,并在构建结束后复核输入文件。环境不符时尽早失败;构建中版本文件漂移则不生成发布清单。`toolchain.mjs` 和配套测试属于正式构建代码,不作为替代真实部署的辅助验收脚本。具体流程见 `build/README.md`。