Optional varighet with start–end display, edge-case tests, CI bumps - #102
Merged
Conversation
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3.7.1 to 4.2.0. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](docker/setup-buildx-action@c47758b...bb05f3f) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-version: 4.2.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.9.0 to 7.3.0. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](docker/build-push-action@4f58ea7...53b7df9) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-version: 7.3.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 5.1.0 to 7.0.0. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](actions/setup-go@41dfa10...b7ad1da) --- updated-dependencies: - dependency-name: actions/setup-go dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](actions/checkout@11bd719...3d3c42e) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Dependabot reads this file from the default branch, so the setting lives on main even though the pull requests land on dev. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Open dependency updates against dev instead of main
…ker/setup-buildx-action-4.2.0 Bump docker/setup-buildx-action from 3.7.1 to 4.2.0
…ker/build-push-action-7.3.0 Bump docker/build-push-action from 6.9.0 to 7.3.0
…ions/setup-go-7.0.0 Bump actions/setup-go from 5.1.0 to 7.0.0
…ions/checkout-7.0.1 Bump actions/checkout from 4.2.2 to 7.0.1
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.3.0 to 4.6.0. - [Release notes](https://github.com/docker/login-action/releases) - [Commits](docker/login-action@9780b0c...dbcb813) --- updated-dependencies: - dependency-name: docker/login-action dependency-version: 4.6.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.6.1 to 6.2.0. - [Release notes](https://github.com/docker/metadata-action/releases) - [Commits](docker/metadata-action@369eb59...dc80280) --- updated-dependencies: - dependency-name: docker/metadata-action dependency-version: 6.2.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Raises the packages that were largely untested: api 0%->100%, config 3.7%->100%, users 32%->100%, assets 67%->100%, httpx 15%->97%, discord 12%->97%, store 60%->96%, auth 50%->94%, events 48%->87%, cmd 21%->52%. The tests are written against current behaviour only. Several document bugs rather than assert they are correct; each of those calls t.Skip with an explanation once the bug is fixed, so it reports rather than blocks. Two packages needed a seam to reach their HTTP paths without a network. discord.APIBase is a constant, so discord and users both drive the client through its nil Transport, swapped for a RoundTripper that rewrites the host and fails the test on any host other than the expected one -- which makes "never touches the network" a checked property. The Mongo query tests assert the struct-tag to query-string correspondence directly, so a field rename breaks loudly without a live server. Verified with -race, -count=2 and -shuffle=on. Nine deliberate defects injected into production code (dropped CSRF empty-cookie guard, disabled alg check, unchecked JWT signature, removed Vary, downgraded board-only gate, dropped login gate, immutable dev assets, cleared HttpOnly, skipped Mongo credential redaction) were all caught. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Correctness and availability: - api: ?page discarded strconv.Atoi's error, and on overflow Atoi returns both MaxInt64 and an error. page * PageSize then wrapped to a negative Skip, which the driver rejects -- an anonymous caller could turn a query string into a 500. Clamped to [1, maxPage]. - cmd: -healthcheck built its URL by concatenating a port, but resolveAddr accepts a bare port, :port or host:port. LISTEN=:3000 -- documented in .env.example -- produced http://127.0.0.1::3000/healthz, so the container reported unhealthy while serving normally. Probe and listener now come from one exported ResolveAddr, split with net.SplitHostPort. :: probes ::1 rather than 127.0.0.1, which an IPv6-only bind would not answer. - httpx: a zero window made Allow divide by zero and store NaN in the bucket, after which every comparison was false and that client was never refused again. A limiter that looks installed but never limits is the failure mode the type exists to prevent, so NewRateLimiter now panics on a non-positive burst or window; both call sites pass constants. - validate: NaN parses and compares false against both bounds, so it passed any range. As a duration it became an end time in 1733, and the event read as finished and vanished from the listing on save. - config: PORT/LISTEN outside 1-65535 now fail at startup rather than in ListenAndServe. PORT=0 is refused: the kernel picks a port the health check cannot find. Wrong thing said to the user: - api, web: fusionauth.parseError wraps every non-2xx, non-404 reply in *APIError, so errors.As matched during an outage and the member was told their registration was invalid. Now split on apiErr.Status. - discord: any 401 claimed the bot token was rejected, but Exchange and currentUser are never sent it -- a reloaded callback pointed operators at the wrong variable. The error now carries which credential was used. - users: a failed guild-membership check was persisted as isMember:false, so the next page told a member to join a server they were already in. The key is now omitted and the last known value kept. Hardening: - users: the email check rejected space and tab but not \n, \r or NUL, and had no length bound; the address is forwarded to an upstream that sends mail. Now rejects all control and space runes, capped at 254. - auth: Inject left a cookie it could not open in the jar, to be re-sent forever. It now clears it, which is what its doc comment always claimed. - auth: quoteJSON escaped only " \ and \n, so any control character made the error body unparseable. Replaced with encoding/json. - auth: ParseForm does not read multipart bodies, so every multipart POST would have 403'd as an expired form. The body bound is unchanged. - discord: the 429 wait was uncapped on a path carrying a request context with no deadline, parking the handler for the whole window. Capped at 5s, and the three linking handlers now carry a 30s deadline. - httpx: gzip mis-parsed RFC-legal whitespace before a q-value and treated q=0 as acceptance; a 206 could also be re-encoded by the middleware. - httpx: RateLimiter leaked a goroutine and a ticker per instance. - config: a UTF-8 BOM made the first .env key unreadable, so FUSION_AUTH_ HOST -- the first line of .env.example -- was reported missing. Documented rather than changed: LISTEN is spent twice by docker-compose, as the host side of the port mapping and, via env_file, as the port the process binds; the container side is hardcoded to 3000, so only a bare 3000 works there. Left alone: linking one Discord account to several members, which needs a product decision -- RemoveMemberRole works by Discord id alone, so one member unlinking strips the shared account's guild role from the other. Verified with -race and MONGO_TEST_URL against MongoDB 8, matching CI. Eleven mutations of the new guards were each caught by a named test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Events without a duration still render just the start time under "Når". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A blank duration is accepted and means the end is unknown: the card shows just the start time, and the edit form pre-fills the field as blank rather than "0". Since end-equals-start would mark a no-duration event "Ferdig" the moment it begins, drop it from the listing six hours after it starts, send Discord a scheduled event that ends when it starts (which it refuses), and put a zero-length sliver in the iCal feed, ComputeEnd now falls back to midnight in Oslo after the start when no duration is set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
martin0x48
approved these changes
Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Everything on
devsince the last release, in three groups:Event duration (varighet) is now optional
tirsdag 1. juli kl 17:15–19:45, spelling out both ends if it crosses midnight). Without one, it shows just the start time as before.endfalls back to midnight (Oslo) after the start. An end equal to the start would mark the event "Ferdig" the moment it begins, drop it from the listing six hours after starting, be refused by Discord (external scheduled events must end after they start), and put a zero-length sliver in the iCal feed.end, and documents missing thedurationkey decode to 0 and render as before.Test hardening
CI / Dependabot
devinstead ofmain.Test plan
go test ./...— all 17 packages pass🤖 Generated with Claude Code