Add proper error handling to prevent silent failures when syncing events
to Google Calendar:
- Add .catch() handler in main.ts webhook to log sync failures
- Add try/catch in create() method to log Google API insert errors
- Improve error handling in remove() method to log get/delete errors
Fixes#10535
Same class of bug fixed in #10442 for graphql calls. The user-scoped
Octokit returned by getOctokit() may lack the .rest plugin, causing
"okit.rest.issues.createComment is not a function". Add ensureRESTOctokit()
guard to both createGithubComment and updateComment paths.
Fixes#10691
Signed-off-by: Yulian Diaz <5605867+spatialy@users.noreply.github.com>
Artyom SavchenkoGitHubCopilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
* fix(github): apply guest token to images in markdown sync (#10516)
The appendGuestLinkToImage function existed but was never called from
getMarkdown(). Add it as the default preprocessor so image URLs include
a guest JWT token, allowing them to render on GitHub.
Signed-off-by: Daniel Kendall <dkendall@ledoweb.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* fix: formatting (prettier/eslint)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
---------
Signed-off-by: Don Kendall <kendall@donkendall.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show the platform version inline on the "Help & Support" navigation
footer button, right-aligned in a subtle style. This follows the
reviewer suggestion to use the existing Help button rather than
adding a separate version label in the settings sidebar.
Signed-off-by: Don Kendall <kendall@donkendall.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When grouping by assignee with a secondary grouping (e.g. by Status),
the "Not Specified" category passed `undefined` as the query value.
Since `undefined` is stripped during JSON serialization, the server
received no filter and returned all documents — causing assigned
issues to appear under "Not Specified".
Use `null` instead so the filter survives serialization and correctly
matches only documents where the field is unset.
Fixes#10606
Signed-off-by: Don Kendall <kendall@donkendall.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(password): add email-confirmed password setup for SSO accounts
SSO-only accounts (Google, GitHub, OIDC) now have a secure path to add
a password credential without requiring direct session trust.
**Problem:** Previously, password setup for SSO users either required an
existing password (blocking SSO-only users entirely) or would have needed
to trust the session token alone to create a persistent credential — a
security gap where a compromised session could silently add a password.
**Solution:** Email-confirmed flow that reuses the existing recovery
infrastructure:
1. `checkHasPassword` RPC — authenticates via session token, returns
whether the account has a password hash set (drives UI branching).
2. `requestPasswordSetup` RPC — authenticates via session token, looks up
the account's verified email social ID, generates a recovery token
(`restoreEmail` claim), and sends a "Password recovery" email via the
existing mail service. No DB schema changes.
3. `PasswordRestore.svelte` (unchanged) handles the link click → calls
the existing `restorePassword` RPC → password is set.
**UI changes** (`Password.svelte`):
- `hasPassword === false` → "Set a password" panel with description and
"Send setup link" button
- On success → "Check your email for a link to set your password."
- On `SocialIdNotFound` → "No email address is linked to your account."
with guidance to add one via Account Settings → Manage Identities
- `hasPassword === true` → existing "Change password" form (unchanged)
**Account client:** Added `checkHasPassword()` and
`requestPasswordSetup()` methods to `AccountClientImpl`; both registered
as platform resource functions (`login.function.CheckHasPassword` /
`login.function.RequestPasswordSetup`).
Signed-off-by: Don Kendall <dkendall@ledoweb.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* test(password): add unit tests for SSO password setup RPCs
ssoPassword.test.ts — 12 tests covering:
- checkHasPassword: returns true/false for hash+salt presence, false for
partial state (hash-only or salt-only), error for missing account
- changePassword: rejects empty old/new passwords, rejects wrong
oldPassword (hash mismatch)
- requestPasswordSetup: sends email when email social ID exists, returns
SocialIdNotFound when no email is linked, handles mail service failures
gracefully (logs error, does not rethrow)
signupTokenGuard.test.ts — added edge-case for empty-string token to
document current guard behaviour (token != null passes empty string
through; noted as a future hardening opportunity).
Signed-off-by: Don Kendall <dkendall@ledoweb.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* chore(dev): add dev-local webpack proxy for local Docker compose stack
Adds a `dev-local` CLIENT_TYPE that proxies webpack dev server requests
to a local Docker compose stack (nginx at localhost:8088), following the
same pattern as the existing `dev-server`, `dev-huly`, etc. modes.
Useful for developing frontend changes against a fully running local
backend without needing `huly.local` DNS configuration.
Signed-off-by: Don Kendall <dkendall@ledoweb.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* feat(email): redesign transactional emails with proper HTML and dedicated password setup template
All account service email templates were bare <p> tags with no styling,
branding, or call-to-action buttons. Replaced with production-quality
HTML emails using email-safe table layout and inline CSS.
Design: Huly wordmark on dark (#18181B) header, white card body, dark
CTA button, subtle border, system font stack. Plain-text versions
updated to match for clients that prefer text.
Templates improved:
- RecoveryHTML/Text — password reset flow
- ConfirmationHTML/Text — email verification on signup
- InviteHTML/Text — workspace invitation
- ResendInviteHTML/Text — re-invitation
- OtpHTML/Text — sign-in code with large monospace code display
New dedicated template for SSO password setup (PasswordSetupHTML/Text/
Subject) so the setup email has copy distinct from forgot-password
recovery. requestPasswordSetup now uses these instead of RecoveryHTML.
Subject: "Set a password for your Huly account".
Other language files updated with the new PasswordSetup* keys
(English copy as fallback — translations can follow separately).
Signed-off-by: Don Kendall <dkendall@ledoweb.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* fix(password): guard requestPasswordSetup against accounts with existing password
Add server-side check that rejects requestPasswordSetup calls from accounts
that already have a password hash+salt. The setup flow bypasses the
old-password requirement in changePassword, so it must be restricted to
SSO-only accounts. The UI already guards this branch but defence-in-depth
requires the server to enforce it independently.
Also adds JSDoc to requestPasswordSetup and extends unit test coverage:
- TokenError path for checkHasPassword (invalid/expired token)
- BadRequest guard for requestPasswordSetup on password-bearing accounts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* fix: add missing locale keys and fix eslint/formatting for CI
- Add 5 missing SSO password translation keys to all non-en locale files
(SetPassword, SSOPasswordDescription, SendSetupLink, SSOPasswordEmailSent,
SSONoEmailLinked) to fix locale parity test
- Replace non-null assertions with type casts in ssoPassword.test.ts
to fix @typescript-eslint/no-non-null-assertion errors
- Revert unrelated tracker/github cosmetic changes that triggered
pre-existing eslint errors in those packages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
* fix: address review — remove dev/prod changes, translate PasswordSetup strings
- Revert dev/prod/webpack.config.js and package.json (per BykhovDenis)
- Translate PasswordSetupText and PasswordSetupSubject for all 10 locales
(cs, de, es, fr, it, pt-br, pt, ru, tr, zh)
- PasswordSetupHTML stays in English (reviewer approved)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
---------
Signed-off-by: Don Kendall <dkendall@ledoweb.com>
Signed-off-by: Don Kendall <kendall@donkendall.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
When a user's name has no spaces (common for CJK names like "西门吹雪"),
name.split(' ') returns a single-element array so the last name
destructures as undefined, causing a PostgreSQL NOT NULL constraint
violation on the last_name column.
- openid: prefer standard OIDC given_name/family_name claims when
available, fall back to splitting name with safe slice(1).join()
- github: same split fix using displayName ?? username
- loginOrSignUpWithProvider: add ?? '' defensive fallback at insertOne
to guard against any undefined last name reaching the DB
Fixes#10628
Signed-off-by: SaiVaraprasad Medapati <varaprasadreddy9676@gmail.com>
Co-authored-by: SaiVaraprasad Medapati <varaprasadreddy9676@gmail.com>
When MAIL_URL is configured the account service intentionally returns
token: undefined to enforce email confirmation before granting access.
SignupForm.svelte was calling logIn() unconditionally, which triggered
PUT /cookie with no Authorization header. The cookie endpoint returned
a 401 whose response body was not parseable as JSON, crashing the client
with "Unexpected token 'N', 'Not Found' is not valid JSON". The account
was created successfully but the user was stuck on the signup page.
- Guard logIn() with `result.token != null`, matching the pattern
already used in doLoginNavigate() in utils.ts
- Fix PUT /cookie 401 response to use ctx.res.writeHead + ctx.res.end
with the JSON body inline, consistent with the rest of the file.
Previously ctx.body was set (Koa pattern) then ctx.res.end() was
called with no body (raw Node pattern), so the body was never sent.
- Add unit tests for the token guard logic
Fixes#10518
Signed-off-by: Don Kendall <kendall@donkendall.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tracker): truncate long milestone titles on issue cards (#9655)
Signed-off-by: Niels Kaspers <kaspersniels@gmail.com>
* style: fix formatting in MilestoneEditor.svelte
Break long div attributes onto separate lines per prettier config.
---------
Signed-off-by: Niels Kaspers <kaspersniels@gmail.com>