13820 Commits

Author SHA1 Message Date
Frederick [Bot]
5ef01965e5 chore(i18n): update translations via Crowdin 2026-04-13 01:48:06 +00:00
kolaente
ab6cdf91eb fix(ci): add debug step to list incoming package files 2026-04-12 19:56:03 +02:00
kolaente
20deac2ce1 fix(ci): rename .archlinux files to .pkg.tar.zst for repo-add
repo-add validates file extensions and rejects .archlinux files.
Rename them to .pkg.tar.zst when symlinking into the repo directory.
2026-04-12 18:32:26 +02:00
kolaente
e1fed9e252 fix(ci): install makepkg for repo-add utility scripts
repo-add from pacman-package-manager sources scripts from
/usr/share/makepkg/util/ which are shipped in the separate
makepkg package on Ubuntu.
2026-04-12 17:59:32 +02:00
kolaente
80ecaeb567 fix(ci): sign APT Release files manually instead of via reprepro gpgme
reprepro uses gpgme for signing which fails in CI environments because
gpgme cannot access pinentry. Instead, remove SignWith from the reprepro
distributions config and sign Release files manually with gpg after
reprepro finishes, producing both Release.gpg and InRelease.
2026-04-12 17:32:11 +02:00
renovate[bot]
160495b84e chore(deps): update dependency stylelint to v17.7.0 2026-04-12 14:42:19 +00:00
kolaente
e8d12186d1 fix(ci): configure gpg loopback pinentry for reprepro signing
reprepro uses gpgme which bypasses the preset passphrase cache and
tries to launch a pinentry dialog, failing in CI with
"Inappropriate ioctl for device". Adding loopback pinentry mode
allows gpgme to obtain the passphrase without a dialog.
2026-04-12 16:49:36 +02:00
kolaente
010be28249 fix(ci): add mage aliases for pacakge releases 2026-04-12 15:04:10 +02:00
kolaente
540beefabc refactor: update reprepro-dist-conf for multi-arch with stable and unstable suites
Update codename from buster to stable, add arm64 and armhf
architectures, pin GPG signing key, and add unstable distribution
for non-release builds.
2026-04-12 12:06:14 +00:00
kolaente
b375399e34 feat(ci): add publish-repos job for OS package repository metadata
New CI job runs after os-package and desktop jobs complete. Downloads
all package artifacts, runs Mage repo targets to generate repository
metadata (APT, RPM, APK, Pacman), GPG-signs the metadata, and uploads
to R2 under /repos/.

Publishes to stable suite for tagged releases, unstable for main
branch builds. Artifact uploads from os-package and desktop jobs are
no longer gated on tags to support this.
2026-04-12 12:06:14 +00:00
kolaente
8cc1a0b30f feat: add Mage targets for OS package repository metadata
Add four new Release namespace targets:
- release:repo-apt — generates APT repo metadata using reprepro
- release:repo-rpm — generates RPM repo metadata via createrepo_c
- release:repo-apk — generates Alpine APK index via apk index + abuild-sign
- release:repo-pacman — generates Pacman database via repo-add

All targets read REPO_SUITE env var (stable/unstable, default stable)
to support publishing to different repository suites.
2026-04-12 12:06:14 +00:00
kolaente
1cde0a1705 feat(ci): add multi-architecture support for OS package builds (#2610) 2026-04-12 12:24:08 +02:00
Claude
85cfadc5b0 fix: fatal with clear message when keyvalue type is redis but redis is not enabled
Instead of panicking with a nil pointer dereference when keyvalue.type
is set to "redis" but redis.enabled is false, log a fatal error with a
clear, actionable message telling the user to enable redis.

Closes go-vikunja/vikunja#2608

https://claude.ai/code/session_01TRuPTGYDQjxqHRFWQaJGvy
2026-04-12 09:43:31 +00:00
kolaente
3e59a654b5 fix(ci): don’t close issue directly 2026-04-12 10:40:42 +02:00
Frederick [Bot]
bacee1597a chore(i18n): update translations via Crowdin 2026-04-12 01:43:16 +00:00
kolaente
f6693f81a2 test(e2e): cover quick add auto-attaching default reminders 2026-04-11 21:51:41 +00:00
kolaente
5afd066a13 feat(tasks): apply default reminders to quick-add tasks with due date
When a user has configured default reminders in their frontend settings,
those are cloned onto every task created via quick-add magic that has a
parsed due date. Tasks without a due date are silently skipped.

The buildDefaultRemindersForQuickAdd helper is exported as a pure
function so it can be unit-tested without stubbing the Pinia store.
2026-04-11 21:51:41 +00:00
kolaente
338d4d8b76 feat(settings): surface quick add default reminders in user settings
Adds the settings field next to the quick add magic mode select, hidden
when that mode is set to Disabled. Uses Reminders.vue directly with
allow-absolute=false and default-relative-to pinned to due date.
2026-04-11 21:51:41 +00:00
kolaente
6c9753328b feat(i18n): add strings for quick add default reminders 2026-04-11 21:51:41 +00:00
kolaente
dc4b7a5510 refactor(reminders): make Reminders.vue take ITaskReminder[] directly
Reminders.vue only read three task fields (dueDate/startDate/endDate)
and wrote one back (reminders). The ITask coupling was accidental.

Flip the prop to ITaskReminder[] and pass defaultRelativeTo / allowAbsolute
as plain props. TaskDetailView now owns the due/start/end priority
computation and binds v-model="task.reminders" directly. This also lets
the settings page reuse Reminders.vue for configuring default reminders.
2026-04-11 21:51:41 +00:00
kolaente
b61ad9d46a feat(reminders): add allowAbsolute prop to ReminderDetail
Adds an allowAbsolute prop to ReminderDetail that hides the 'Date and
time' option when set to false, and a lockRelativeTo prop on
ReminderPeriod that hides the relativeTo select and forces the chosen
value. ReminderDetail threads them together so that when absolute
reminders are disallowed, the Custom form can only produce reminders
that anchor to defaultRelativeTo.
2026-04-11 21:51:41 +00:00
kolaente
e85f3fd84c feat(settings): add quickAddDefaultReminders field to frontend settings 2026-04-11 21:51:41 +00:00
Frederick [Bot]
9a12c8f254 [skip ci] Updated swagger docs 2026-04-11 21:00:40 +00:00
kolaente
c06a33fb63 test(e2e): mirror task id to index in TaskFactory
Multiple TaskFactory.create(1, {id: N, ...}, false) calls for the same
project were all defaulting to index=1 (from {increment} with count=1),
which collides on the newly added UNIQUE(project_id, index) constraint.
Mirror the numeric id override to index so each row stays unique and
matches the id == index convention used by raw seedTasks helpers.

Fixes the e2e playwright seed failures in subtask-duplicates, list/table
filter/search, kanban filter/search, and overview specs.
2026-04-11 20:44:28 +00:00
kolaente
8578fe3468 feat(api): add GET /projects/:project/tasks/by-index/:index endpoint 2026-04-11 20:44:28 +00:00
kolaente
9206f98d64 feat(tasks): enforce unique (project_id, index) via migration 2026-04-11 20:44:28 +00:00
kolaente
8f9b50bdcb feat(tasks): add GetTaskByProjectAndIndex resolver 2026-04-11 20:44:28 +00:00
kolaente
ced7ebd97f fix(auth): tolerate string booleans in oidc provider config (#2599)
The four boolean OIDC provider fields (emailfallback, usernamefallback,
forceuserinfo, requireavailability) were parsed with a strict .(bool)
type assertion. That works for YAML/JSON config where leaves are native
bools, but fails for every other input path: env vars always arrive as
strings, and GetConfigValueFromFile (used by the *.file Docker secret
convention) also always returns strings. The assertion would silently
zero the field for emailfallback and usernamefallback, and log an error
and zero the field for forceuserinfo and requireavailability, which is
what #2599 reports.

Extract a small parseBoolField helper that accepts both native bools and
strings (via strconv.ParseBool) and logs a parse error from each call
site. This also fixes the previously-silent drop of stringified
emailfallback / usernamefallback values — those now log an error if the
input is garbage, matching the behaviour of the other two fields.

Fixes #2599
2026-04-11 19:10:26 +00:00
kolaente
3008dc09db test(auth): cover env-var string booleans for oidc providers (#2599)
Regression test for #2599. Exercises getProviderFromMap with native
bools and with stringified booleans ("true"/"false"/"1"/"0") for all
four boolean provider fields — emailfallback, usernamefallback,
forceuserinfo, requireavailability. From env vars and from the
GetConfigValueFromFile path every leaf arrives as a string, so the
current .(bool) assertion silently zeros these fields.
2026-04-11 19:10:26 +00:00
kolaente
113b77e92f fix(modal): skip showModal if enabled flipped false before mount
Re-check props.enabled inside the dialogRef watcher. The watcher fires
once Vue mounts the <dialog>, but the caller may have flipped enabled
back to false between the openDialog() call and the mount flush. In that
case the prop state is disabled and we must not open the dialog.

Addresses augmentcode review on #2604.
2026-04-11 19:00:43 +00:00
kolaente
e01a599418 fix(modal): clear stale data-closing flag when re-opened mid-close
If the modal is re-enabled within the 150ms close transition the
<dialog> element is still mounted and [open], so the dialogRef watcher
does not re-fire. Clear the leftover data-closing flag directly in
openDialog() so the dialog doesn't remain stuck at opacity 0.

Addresses augmentcode review on #2604.
2026-04-11 19:00:43 +00:00
kolaente
e932ee759a fix(modal): open dialog reliably in electron desktop
Replace the nextTick-based showModal() call with a watch on the template
ref so the dialog is opened exactly when the <dialog> element mounts.
The previous implementation could silently skip showModal() if the mount
was deferred past the first nextTick, leaving the dialog in the DOM with
opacity: 0 and no click target. Observed in the Vikunja Desktop v2.3.0
Electron build where the search (quick actions) button was unresponsive.

Closes #2590
2026-04-11 19:00:43 +00:00
kolaente
f29f985386 test(modal): cover open race for #2590 2026-04-11 19:00:43 +00:00
kolaente
a11abb46b4 ci: add tests using mysql-8 2026-04-11 17:20:53 +00:00
kolaente
5b2cbcb1b5 fix(project): replace CAST(... AS int) with CASE WHEN for MySQL 8 compat
MySQL 8 rejects CAST(... AS int) (only SIGNED/UNSIGNED/CHAR/... are
accepted as target types), causing /api/v1/projects, /api/v1/tasks,
and /api/v1/labels to return HTTP 500 for every authenticated user on
MySQL 8. SQLite, Postgres, and MariaDB lax mode silently accepted the
expression, which is why the regression (introduced in e3045dfd0,
shipped in v2.3.0) passed CI — the mysql CI matrix leg uses
mariadb:12, not real MySQL 8.

Replace the two CAST(all_projects.is_archived AS int) expressions in
the recursive project CTE with MAX(CASE WHEN ... THEN 1 ELSE 0 END),
which is dialect-agnostic and needs no cast on any supported backend.

Fixes #2589
2026-04-11 17:20:53 +00:00
kolaente
3b7996feef test(project): pin archived propagation aggregation in ReadAll CTE
Regression test for #2589. Locks the contract that getAllProjectsForUser
exposes inherited is_archived for child projects of archived parents and
filters them out when getArchived=false, exercising both the MAX(...)
column expression and the HAVING MAX(...) = 0 filter.
2026-04-11 17:20:53 +00:00
kolaente
c9809f1385 fix(ci): use working model 2026-04-11 17:55:47 +02:00
kolaente
c4cc6d34f6 ci: add AI-powered auto-labeling for new issues and PRs
Uses actions/ai-inference with GPT-5 to classify newly opened issues
and pull requests against the area/*, integration/*, db/*, and
concern/* label namespaces.

The system prompt is rendered at runtime from the live repo label list
plus descriptions, so GitHub label state is the single source of truth
for the taxonomy. Suggested labels are re-validated against the live
list before being applied, capped at 6 per item.
2026-04-11 17:45:36 +02:00
kolaente
2796fffbc1 fix(ci): skip interactive prompt in nixpkgs update workflow
The nixpkgs update.py script prompts for confirmation before running,
which fails with EOFError in CI since there is no TTY. Pass skip-prompt
to maintainers/scripts/update.nix to bypass the prompt.
2026-04-11 15:00:42 +00:00
Frederick [Bot]
50d6926b56 chore(i18n): update translations via Crowdin 2026-04-11 01:20:45 +00:00
renovate[bot]
df7a5c645c chore(deps): update dependency wait-on to v9.0.5 2026-04-10 22:57:21 +00:00
dependabot[bot]
e8c20b1244 chore(deps): bump axios from 1.13.5 to 1.15.0 in /frontend
Bumps [axios](https://github.com/axios/axios) from 1.13.5 to 1.15.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.5...v1.15.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-version: 1.15.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-10 09:58:30 +00:00
kolaente
28b537837f chore: v2.3.0 release preparations v2.3.0 2026-04-09 20:43:40 +02:00
Frederick [Bot]
a193ac14c2 [skip ci] Updated swagger docs 2026-04-09 17:42:29 +00:00
kolaente
b642b2a453 feat(auth): prompt for TOTP code in the OIDC callback flow
When the backend reports that 2FA is required (412/1017), the OIDC
callback view now shows a TOTP input and restarts the OIDC dance
with the typed passcode stashed in localStorage so it can be
submitted alongside a fresh authorization code.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente
546db0dc21 feat(auth): plumb totp passcode through openIdAuth action
Allows the OpenIdAuth view to resubmit the OIDC callback with a
TOTP passcode after a 412/1017 response from the backend.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente
d58dd7a7c6 fix(auth): enforce TOTP on OIDC callback for users with 2FA enabled
The OIDC callback handler previously issued a JWT without ever
checking TOTP state. For installations with EmailFallback (or
UsernameFallback) enabled, this allowed an attacker who could
authenticate at the IdP with a matching email to log in as a local
user with TOTP enrolled, bypassing the second factor entirely.

HandleCallback now runs enforceTOTPIfRequired after resolving the
user and before any team sync writes, returning 412/1017 when the
passcode is missing or invalid. Clients resubmit the OIDC flow with
the totp_passcode field populated.

Fixes GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente
c52b2a4f83 feat(auth): add enforceTOTPIfRequired helper for OIDC flow
Extracts a TOTP gate that the OIDC callback will use to enforce 2FA
for users with TOTP enabled. Mirrors the local-login TOTP flow in
pkg/routes/api/v1/login.go. Not yet wired into HandleCallback.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente
d291e3effe test(auth): add failing unit tests for OIDC TOTP enforcement
Covers the four states the OIDC TOTP gate must handle: user without
TOTP, TOTP enabled with missing passcode, invalid passcode, and
valid passcode. The helper function under test does not exist yet,
so the package currently fails to compile.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00
kolaente
2b980be20d refactor(auth): add TOTPPasscode to OIDC Callback payload
Prepares the OIDC callback struct to carry a TOTP passcode so the
handler can enforce 2FA for users with TOTP enabled. No behaviour
change yet.

Refs GHSA-8jvc-mcx6-r4cg
2026-04-09 17:25:47 +00:00