Artifact 404ab6ddfe8041156fad21b3904ba2ef2092171755abc1a1547760c6165076af:
- File
conformance/sync_login_test.go
— part of check-in
[80c72b27c7]
at
2026-10-11 13:57:34
on branch main
— test(conformance): sync-protocol conformance suite (#262) (#311)
* test(conformance): sync-protocol conformance suite (#262)
Checks go-libfossil against draft-fossil-sync-protocol-00, requirement by requirement: 149 requirements, 199 cases. Server cases send raw requests to Repo.XferHandler and, through `fossil http --in`, to fossil(1) on a copy of the same repository; client cases drive the public Sync and Clone against a scripted peer, with fossil(1)'s client run against the same script for most of them; HTTP cases cover redirects, status codes and media types; interop cases run whole exchanges in both directions.
Known failures are marked with the placeholder #0 until their issues are filed, so TestCoverage fails until then.
* test(conformance): sync suite review fixes (#262)
Cases for the requirements that had none where fossil(1) can show the behavior: server-version, the SHA3 gate, shun admission, cookie and cleartext logins, pushed configuration, ci-unlock, cluster brackets, the clone's unversioned catalog and the pull-only message. Two rows added: link ARG handling and the short uvigot.
A fossil(1) disagreement, a harness failure or a deviation other than the one named now fails a case whatever its mark. The server's log output is discarded in the tests.
* test(conformance): mark sync gaps with their issues; drop gaps v0.11.1 closed (#262)
v0.11.1's read gate and redirect policy make seven sync cases conform, so their gap marks are removed. The rest are marked with the issues that track each fix: #296 and #299-#310.
* test(conformance): accept either fossil refusal of a negative clone SEQNO
fossil 2.28's macOS build answers clone 3 -1 with clone_seqno 0 and its Linux build, which CI pins, with the invalid-sequence error alone. The draft leaves the reply open; the case now holds go-libfossil only to sending no content. (user: [email protected], size: 2232) [annotate] [blame] [check-ins using]
package conformance import ( "strings" ) // Login cards are built here from the draft's formulas (Sections 6.2 to // 6.4), not by go-libfossil's own computeLogin, so a case cannot agree with // the client by sharing its mistake. // sharedSecret is SHA1(project-code "/" login "/" password), Section 6.3. func sharedSecret(projectCode, login, password string) string { return sha1Hex(projectCode + "/" + login + "/" + password) } // signature is SHA1(NONCE-hex || shared-secret-hex), Section 6.4. func signature(nonce, secret string) string { return sha1Hex(nonce + secret) } // sign replaces each "{LOGIN user password [how]}" line of body with a login // card whose nonce covers every byte after that line (Section 6.2). Lines // are signed from the last up, so an earlier login covers a later one. how // changes one thing about an otherwise correct card: // // upper the signature in uppercase hex // zero a signature of forty zeros // stale a nonce over the body with one byte more, as when the body // changed after it was signed func (f *syncFixture) sign(body string) string { parts := strings.SplitAfter(body, "\n") for i := len(parts) - 1; i >= 0; i-- { line := strings.TrimSuffix(parts[i], "\n") if !strings.HasPrefix(line, "{LOGIN ") || !strings.HasSuffix(line, "}") { continue } args := strings.Fields(strings.TrimSuffix(strings.TrimPrefix(line, "{LOGIN "), "}")) if len(args) != 2 && len(args) != 3 { panic("conformance: login placeholder " + line) } tail := strings.Join(parts[i+1:], "") how := "" if len(args) == 3 { how = args[2] } parts[i] = loginLine(f.vars["PC"], args[0], args[1], how, tail) + "\n" } return strings.Join(parts, "") } // loginLine is the login card for user over tail. func loginLine(projectCode, user, password, how, tail string) string { nonce := sha1Hex(tail) if how == "stale" { nonce = sha1Hex(tail + "x") } sig := signature(nonce, sharedSecret(projectCode, user, password)) switch how { case "", "stale": case "upper": sig = strings.ToUpper(sig) case "zero": sig = strings.Repeat("0", 40) default: panic("conformance: unknown login change " + how) } return "login " + fossilize(user) + " " + nonce + " " + sig }