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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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
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
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.
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.
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.
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
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
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
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
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