diff --git a/src/commit.ts b/src/commit.ts index 296086c..a11bdd5 100644 --- a/src/commit.ts +++ b/src/commit.ts @@ -84,12 +84,26 @@ export function parseRawCommit(oid: string, raw: string): Commit { ); } - if (headers.some((line) => line.startsWith("gpgsig "))) { + if ( + headers.some( + (line) => line.startsWith("gpgsig ") || line.startsWith("gpgsig-sha256 "), + ) + ) { throw new Error( `Commit ${oid} is signed. bstack cannot add an identity trailer without replacing its signature`, ); } + const encoding = headers + .find((line) => line.startsWith("encoding ")) + ?.slice("encoding ".length); + + if (encoding && !/^utf-?8$/i.test(encoding)) { + throw new Error( + `Commit ${oid} uses the ${encoding} message encoding; bstack only supports UTF-8 commit messages`, + ); + } + const message = raw.slice(boundary + 2); return { diff --git a/test/commit.test.ts b/test/commit.test.ts index f138c44..f2e85ba 100644 --- a/test/commit.test.ts +++ b/test/commit.test.ts @@ -53,6 +53,42 @@ describe("commit identity", () => { }); }); + test.each([ + ["gpgsig -----BEGIN PGP SIGNATURE-----", "is signed"], + ["gpgsig-sha256 -----BEGIN PGP SIGNATURE-----", "is signed"], + ["encoding ISO-8859-1", "uses the ISO-8859-1 message encoding"], + ])("rejects commits with the %s header", (header, message) => { + const raw = [ + "tree aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "parent bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "author Ada 1 +0000", + "committer Ada 1 +0000", + header, + "", + "Original message", + "", + ].join("\n"); + + expect(() => + parseRawCommit("cccccccccccccccccccccccccccccccccccccccc", raw), + ).toThrow(message); + }); + + test("accepts an explicit UTF-8 encoding header", () => { + const raw = [ + "tree aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "parent bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "encoding UTF-8", + "", + "Original message", + "", + ].join("\n"); + + expect( + parseRawCommit("cccccccccccccccccccccccccccccccccccccccc", raw).message, + ).toBe("Original message\n"); + }); + test("rewrites only the parent and message of a raw commit", () => { const raw = [ "tree aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",