1e6bacd9a98d

close the joint test's review: prove the explicit offer, every field, and the clock-order prune (v3.0.67)

time
2026-09-27 16:17 UTC · 2 weeks ago
machine
Junes-MacBook-Pro.local
agent
deepseek/deepseek-flash
session
kepr connect and public steal
parent
fe8c5250fc91
4 files package.json+1 −1tests/connect.test.ts+19 −0tests/kohremote.test.ts+7 −2tests/kohsteal.test.ts+10 −6
package.json+1 −1
@@ -1,6 +1,6 @@11 {22 	"name": "kepr",3-	"version": "3.0.66",3+	"version": "3.0.67",44 	"private": true,55 	"type": "module",66 	"scripts": {

view file

tests/connect.test.ts+19 −0
@@ -242,6 +242,25 @@242242 		expect((await redeem(app, fresh, "192.0.2.40")).status).toBe(200);243243 	});244244 245+	test("the attempt window is counted by time, not by the list's order", async () => {246+		const { app, browser } = await connected();247+		const address = "192.0.2.70";248+		// Nine attempts at one moment...249+		for (let i = 0; i < 9; i++) await redeem(app, "bad", address);250+		// ...then the clock steps back — an NTP correction, or a test's fake timer — and a tenth251+		// attempt lands *older* than the nine before it. A prune that walks the list by position252+		// stops at the first entry still inside the window and never reaches that one.253+		clock -= 120_000;254+		setSystemTime(clock);255+		await redeem(app, "bad", address);256+		// Now: an hour and two minutes after the nine, so the older tenth has left the window while257+		// they are still inside it — the peer has one attempt left, not none.258+		clock += 3_620_000;259+		setSystemTime(clock);260+		const { code } = await issue(browser, "after the step");261+		expect((await redeem(app, code, address)).status).toBe(200);262+	});263+245264 	test("a forged X-Forwarded-For does not buy another bucketful", async () => {246265 		const { app, browser } = await connected();247266 		const { code } = await issue(browser);

view file

tests/kohremote.test.ts+7 −2
@@ -80,11 +80,14 @@8080 8181 	test("the save and object prefixes list what a clone walks", async () => {8282 		const saves = await get("saves");83+		expect(saves.status).toBe(200);8384 		expect(saves.headers.get("cache-control")).toBe("no-cache");8485 		expect((await saves.text()).trim().split("\n")).toContain(head);8586 		const save = await record(head);86-		const objects = await (await get("objects")).text();87-		expect(objects.trim().split("\n")).toContain(save.files[0].hash);87+		const objects = await get("objects");88+		expect(objects.status).toBe(200);89+		expect(objects.headers.get("cache-control")).toBe("no-cache");90+		expect((await objects.text()).trim().split("\n")).toContain(save.files[0].hash);8891 	});8992 9093 	test("an object is the stored zlib bytes and hashes back to its key", async () => {@@ -129,6 +132,8 @@129132 				"format",130133 				"head",131134 				"events",135+				"saves",136+				"objects",132137 				`saves/${head}`,133138 				`objects/${"a".repeat(64)}`,134139 				`events/${"b".repeat(12)}`,

view file

tests/kohsteal.test.ts+10 −6
@@ -73,10 +73,9 @@7373 	return { code, out, err };7474 }7575 76+/** The whole line, every field of every save: what a clone must reproduce exactly. */7677 async function line(repo: string, home: string): Promise<unknown> {77-	return JSON.parse((await koh3(repo, home, ["view", "--json"])).out).saves.map(78-		(save: { id: string; message: string }) => [save.id, save.message],79-	);78+	return JSON.parse((await koh3(repo, home, ["view", "--json"])).out).saves;8079 }8180 8281 describe.serial("stealing a public repo from Kepr over HTTP", () => {@@ -225,11 +224,16 @@225224 				const upgraded = await koh3(clone, thiefHome, ["offer"]);226225 				expect(upgraded.code, upgraded.err + upgraded.out).toBe(0);227226 				expect(upgraded.out + upgraded.err).toContain("now syncs with your bucket");227+				// The owner can read what that offer published, before anything else is saved: the228+				// local save the clone was carrying went up with it.229+				expect((await koh3(repoDir, ownerHome, ["revert", "--yes"])).code).toBe(0);230+				expect((await koh3(repoDir, ownerHome, ["steal"])).code).toBe(0);231+				expect(await readFile(join(repoDir, "local.txt"), "utf8")).toContain("work in progress");232+				expect(JSON.parse((await koh3(repoDir, ownerHome, ["view", "--json"])).out).saves).toEqual(233+					JSON.parse((await koh3(clone, thiefHome, ["view", "--json"])).out).saves,234+				);228235 				await writeFile(join(clone, "README.md"), "# shipped\n\nThe thief's edit.\n");229236 				expect((await koh3(clone, thiefHome, ["save", "from the thief"])).code).toBe(0);230-				// The owner steals it back from the bucket; the stripped file is unsaved work there231-				// too, so it goes first.232-				expect((await koh3(repoDir, ownerHome, ["revert", "--yes"])).code).toBe(0);233237 				expect((await koh3(repoDir, ownerHome, ["steal"])).code).toBe(0);234238 				expect(await readFile(join(repoDir, "README.md"), "utf8")).toContain("The thief's edit");235239 

view file