Align session codec max-age with the 7-day cap (closes #108) #132
Reference in New Issue
Block a user
Delete Branch "issue-108-session-codec-maxage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #108
What changed
internal/session/session.go: the cookie store is now built bynewStore, which applies the cap withstore.MaxAge(secondsPerDay * sessionMaxAgeDays)instead of assigningstore.Options.NewCookieStoregives its securecookie codecs a 30-day max age of their own that assigningOptionsnever touches;store.MaxAgesetsOptions.MaxAgeand every codec.newStoreis the only place a store is constructed, andRegeneratenow shares the cookie attributes throughcookieOptionsso the two cannot drift.internal/session/codec_test.go(new): two tests that decode a re-stamped cookie one hour inside and one hour outside the cap. They callSession.Getonly, which decodes and nothing else, so no server-side expiry check takes part.restampreproduces the securecookie wire format because securecookie stamps the encoding time itself and exposes no seam to move it.internal/session/session_test.go: the test store is now built by the production constructor (exported viaexport_test.go) rather than a lookalike, andTestTouch_RefreshThresholdIsOneTenthOfIdleWindowpinsidleRefreshDivisorfrom both sides.internal/middleware/middleware.go: item 2 — theSaveerror is scoped to its ownsaveErrvariable instead of reusing the outererr. It is a plain assignment rather than an inlineif saveErr := ...; saveErr != nil, because the repo'snoinlineerrlinter rejects that form. Behaviour is unchanged: this is the scoping hygiene item 2 asked for, not a bug fix. The pre-change log site reassignederrfromSaveon the line directly above the check, so it always carried the save error.README.md: item 4 — the idle timeout is disabled by any non-positive value, not only0; and deploying the two-clock expiry logs every existing session out once, because those sessions carry nocreated_at/last_seen.TODO.mdand.golangci.ymluntouched.Item 3: declined
fakeClockis duplicated ininternal/sessionandinternal/middlewaretests. The issue conditions folding it into a shared helper on a third use appearing; there is no third use, so it stays duplicated, as does the helper that returns the*fakeClockit was handed.Mutation proofs
Codec test,
make testeach time:TestCodec_RejectsCookiePastAbsoluteCapstore.MaxAge(...)reverted tostore.Options.MaxAge = ...codec_test.go:130, therequire.Error) — and the only failure in the suite: everyexpired-based test still passed, which is the skew the issue describesexpiredstubbed toreturn falseexpiredstubbed toreturn falseDivisor test,
TestTouch_RefreshThresholdIsOneTenthOfIdleWindow:idleRefreshDivisor105Touchtest still passed20Gate
make checkexit 0 on the rebased branch (test, lint, fmt-check).docker build --no-cache-filter=lint,builderexit 0, stages executed rather than cached:#20 [lint 7/8] RUN make fmt-check,#21 [lint 8/8] RUN make lint→0 issues.,#29 [builder 8/10] RUN make test→ok sneak.berlin/go/webhooker/internal/session 1.078swith all three new tests listed PASS. No prune was used; only the two stages under test were invalidated.One pre-existing warning surfaced by the pinned linter, out of scope here and not acted on:
gomodguardis deprecated since v2.12.0 in favour ofgomodguard_v2, which would be a.golangci.ymlchange.Rework
Commit
37b665a→618b07c: commit message only. The tree is unchanged (git diff 37b665a HEADempty, identical tree objectf4a9033), so the review's mutation matrix and containerized gate on that tree still hold. The amended body drops the bug-fix claim for themiddleware.gochange and describes it as scoping, matching the text above.make checkre-run on the amended commit: exit 0.FAIL - needs-rework. One finding.
1.
internal/middleware/middleware.go:217- the commit message and PR description assert a bug that did not exist. The pre-change code was:erris reassigned fromSaveon the line immediately above the check, so the log site could only ever carry the save error. It was never the nilsession.Geterror. The commit body ("Also fixes the RequireAuth save error"), the PR description ("This also fixed a live bug the rename exposed: the log line read"error", err- the outer, nil error fromsession.Get, not the save error"), and the comment on #108 all claim a live logging defect was repaired. There was none - item 2 of #108 itself calls the pattern "harmless". The code change is correct and is exactly the scoping item 2 asked for; only the claim is false, and with squash merge it lands in permanent history. Acceptable: amend the commit body and correct the PR description to describe this as the scoping cleanup it is, with no bug-fix claim.Verified clean (reproduced independently, not read from the PR body):
store.MaxAgepropagates to every codec (gorilla/sessions@v1.4.0store.go:121-130) andnewStoreis the only production construction site; reverting tostore.Options.MaxAgemakesTestCodec_RejectsCookiePastAbsoluteCapthe suite's sole failure, it still fails withexpiredstubbed toreturn false, and both codec tests pass with the fix in place andexpiredstubbed - the test pins the codec, not the server check; the divisor test fails at 5 and at 20; no other stale-errlog site inmiddleware.go;cookieOptionsgives byte-identical attributes on the initial andRegeneratepaths; both README claims check out (envDurationaccepts negative durations andidleTimeout <= 0disables;expiredreturns true on missingcreated_at);make fmtis a no-op; basenext, single commit, title suffix,TODO.mdand.golangci.ymluntouched, no attribution trailers; merges cleanly ontonextatfd63971.Gate:
docker build --no-cache-filter=lint,builder --progress=plain .exit 0 -#18 [lint 7/8] RUN make fmt-checkDONE 3.3s,#19 [lint 8/8] RUN make lintDONE 67.7s ->0 issues.,#34 [builder 8/10] RUN make testDONE 107.1s with all three new tests listed PASS. Executed, not CACHED; lint ran in the pinned container only.Disclosures: the Gitea status on
37b665ais stillpending("Waiting to run", run 143) rather than green, and the Actions API 403s for this account, so CI green is unverified - the uncached container gate above is the evidence I have. Item 3's decline is defensible: the issue conditioned foldingfakeClockon a third use and there is none. Not filed, for the record:internal/middleware/middleware_test.go:67and:850still assemble lookalike stores withstore.Options(30-day codecs), so "the only place a store is constructed" holds for production but not for tests outside packagesession.37b665a22fto618b07ca0fPASS - scoped re-review of the amend. Tree byte-identical (
37b665aand618b07cboth atf4a903346803da87867966ce93d2495b62ff72ab,git diffbetween them empty, same parentd19e336); the false bug-fix claim is gone from the commit body and the PR description, and the comment on #108 was edited rather than supplemented; the replacement text is true (reproduced: the inline form yieldsmiddleware.go:217:8 ... (noinlineerr)as the sole lint issue,erris dead after the block so behaviour is unchanged;idleTimeout <= 0disables idle expiry andexpiredreturns true on missingcreated_at, backing both README claims); still one commit on basenext, merges clean atfd63971, title suffix present, no attribution anywhere;make checkexit 0 (session package ran 1.079s, not cached;0 issues.). CI green on618b07c:check / check (push)success, "Successful in 3m5s" (run 145).Disclosures: I did not re-run the containerized gate or the mutation matrix - I rely on the gate evidence in #132 (comment), which is sound because the amend changed only the commit object and the tree tested there is the same bytes. My
make checkran the linter on the host (script/lintis not containerized in this repo; the container path isscript/cibuild), so that lint result is corroboration, not the gate. Edited once after posting, to record CI turning green - it was still queued at the time of the original verdict.PASS — independent re-review of
618b07cagainstorigin/nextd8f9d14: DoD of #108 met, mutations reproduced from scratch (reverting tostore.Options.MaxAgemakesTestCodec_RejectsCookiePastAbsoluteCapthe suite's sole failure and it still fails withexpiredstubbed toreturn false, while both codec tests pass with the fix in place andexpiredstubbed; the divisor test fails at both 5 and 20),store.MaxAgepropagation and the per-sessionopts := *s.Optionscopy confirmed ingorilla/sessions@v1.4.0store.go:92,120-130, no forced logouts possible since the codec deadline is encode-time+7d and encode time is never beforecreated_at, both README claims check out (envDurationerrors on unparseable and passes negatives through,idleTimeout <= 0disables,expiredreturns true on missingcreated_at), merges clean into currentnext(git merge-treeexit 0; onlyREADME.mdoverlaps and the merged text reads coherently), CI success on618b07c(run 145, 3m5s), title suffix present,TODO.md/.golangci.ymluntouched, no attribution anywhere in tree or commit. Gate:docker build --no-cache-filter=lint --no-cache-filter=builderexit 0 —#18 [lint 7/8] RUN make fmt-checkDONE 1.2s,#19 [lint 8/8] RUN make lintDONE 74.0s ->0 issues.,#26 [builder 8/10] RUN make testDONE 72.6s ->ok sneak.berlin/go/webhooker/internal/session 1.087swith zero(cached)markers anywhere in the output and all three new tests PASS. Disclosures: hostmake checkexited 2 onError: parallel golangci-lint is running— the known shared-host lock, not a finding; tests within it passed (session 1.069s, uncached), and the container run above is the lint evidence. Two mutation probes usedgo test -run TestCodecdirectly becausemake testhas no filter. Not filed, for the record:internal/middleware/middleware_test.go:67and:850still assemble lookalike stores viastore.Options(30-day codecs), and becauseNewStoreis exported throughexport_test.gopackagemiddlewarecannot reach it — no test there asserts on codec age so nothing is falsely green, but the commit body's "the one place a store is constructed" holds for production only. Branch is 4 commits behindnext; that is a fast-forwardable gap, not a conflict.