Commit Graph
290 Commits
Author SHA1 Message Date
d9c184777e [AI] Document intended global bank-sync credential access in sync-server (#9439)
* [AI] Document intended global bank-sync credential access in sync-server

Global bank-sync credentials are usable by any authenticated user by
design; add a note so this stops being reported as a vulnerability.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8X9eQbJYThmFWQRnxw1Q6

* [AI] Add SECURITY.md with threat model and align bank-sync comments

Document how to report vulnerabilities, the trusted-users threat model
for multi-user servers, and that shared global bank-sync credentials are
out of scope. Point the sync-server comments at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8X9eQbJYThmFWQRnxw1Q6

* [AI] Clarify per-budget credential advice in SECURITY.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8X9eQbJYThmFWQRnxw1Q6

* [AI] Add release note for security policy

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8X9eQbJYThmFWQRnxw1Q6

* [AI] Tighten security note wording on route scope and per-budget credentials

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q8X9eQbJYThmFWQRnxw1Q6

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-05 18:27:25 +00:00
0b1eec8cce [AI] Reject sync messages too far in the future (#8905)
* #7106 - Reject incoming messages with explicit 400 error when they're going to cause permanent clock drift issues

* Generate release notes

* Simplify release note

* Use >= for future check, and use functional error factory vs creating new error type

* PR feedback: only check new messages for invalid timestamps

* PR feedback: check for invalid timestamps and use a separate error for them

* [AI] Reduce clock drift sync tests

* [AI] Simplify sync timestamp rejection

* [AI] Always restore real timers in sync resend test

* [AI] Assert rejected sync messages are rolled back

* [AI] Tidy clock drift comment and release note

* [AI] Match server future-drift limit to client maxDrift

* [AI] Test the five-minute future-drift boundary

* [AI] Match client drift comparison at the boundary

---------

Co-authored-by: Tim Smart <hello@timsmart.co>
2026-11-03 04:07:55 +00:00
6330c716ce [AI] Upgrade akahu to 2.6.0 (#9411)
Drops the deep import of EnrichedPendingTransaction, which 2.6.0 folds
into PendingTransaction.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 21:09:34 +00:00
github-actions[bot]GitHubgithub-merge-queuegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Julian Dominguez-Schatz
741d1615b7 🔖 (26.11.0) (#9321)
* 🔖 (26.11.0)

* Generate release notes for v26.11.0

* Generate release notes for v26.11.0

* [AI] Add November release highlights and upgrade notices

* Generate release notes for v26.11.0

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>
2026-11-02 00:11:25 +00:00
Dami OyeniyiGitHubgrzdevautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>Tim Smart
fa10ddb9de [AI] Fall back to IPv4 when binding to IPv6 is unavailable (#9226)
* [AI] Fall back to IPv4 when binding to IPv6 is unavailable

* [autofix.ci] apply automated fixes

* fix(sync-server): handle fallback listen errors and fix test typings

* [autofix.ci] apply automated fixes

* fix(sync-server): close server and propagate error on terminal listen failures

* [AI] Minimize sync server listen tests

* [AI] Use Node's default binding for IPv4 fallback

* [AI] Assert default host is omitted when listening

* [AI] Simplify listen test and startup message naming

* [AI] Tighten listen comment and release note

---------

Co-authored-by: grzdev <grzdev@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Tim Smart <hello@timsmart.co>
2026-10-30 04:36:28 +00:00
Julian Dominguez-SchatzandGitHub dff6b4b21b [AI] Standardize server fetch on Undici (#9351) 2026-10-27 19:19:21 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
449ade7bed Bump postcss-selector-parser (#9333)
Bumps the npm_and_yarn group with 1 update in the / directory: [postcss-selector-parser](https://github.com/postcss/postcss-selector-parser).


Updates `postcss-selector-parser` from 6.1.4 to 6.1.5
- [Release notes](https://github.com/postcss/postcss-selector-parser/releases)
- [Changelog](https://github.com/postcss/postcss-selector-parser/blob/6.1.5/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-selector-parser/compare/6.1.4...6.1.5)

---
updated-dependencies:
- dependency-name: postcss-selector-parser
  dependency-version: 6.1.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 20:47:33 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d0dd62899c Bump body-parser (#9323)
Bumps the npm_and_yarn group with 1 update in the / directory: [body-parser](https://github.com/expressjs/body-parser).


Updates `body-parser` from 1.20.8 to 1.20.9
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/1.20.9/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.8...1.20.9)

---
updated-dependencies:
- dependency-name: body-parser
  dependency-version: 1.20.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-26 11:21:52 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2c75d28ec5 Bump the npm_and_yarn group across 2 directories with 4 updates (#9317)
Bumps the npm_and_yarn group with 4 updates in the / directory: [electron](https://github.com/electron/electron), [dompurify](https://github.com/cure53/DOMPurify), [fast-uri](https://github.com/fastify/fast-uri) and [ip-address](https://github.com/beaugunderson/ip-address).
Bumps the npm_and_yarn group with 1 update in the /packages/desktop-electron directory: [electron](https://github.com/electron/electron).


Updates `electron` from 43.8.0 to 43.8.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.8.0...v43.8.1)

Updates `dompurify` from 3.4.16 to 3.4.17
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.4.16...3.4.17)

Updates `fast-uri` from 3.1.8 to 3.1.9
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.8...v3.1.9)

Updates `ip-address` from 10.7.2 to 10.7.4
- [Release notes](https://github.com/beaugunderson/ip-address/releases)
- [Commits](https://github.com/beaugunderson/ip-address/compare/v10.7.2...v10.7.4)

Updates `electron` from 43.8.0 to 43.8.1
- [Release notes](https://github.com/electron/electron/releases)
- [Commits](https://github.com/electron/electron/compare/v43.8.0...v43.8.1)

---
updated-dependencies:
- dependency-name: electron
  dependency-version: 43.8.1
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: dompurify
  dependency-version: 3.4.17
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: fast-uri
  dependency-version: 3.1.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: ip-address
  dependency-version: 10.7.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: electron
  dependency-version: 43.8.1
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-25 18:48:01 +00:00
168e174b47 [AI] Make file writes atomic (#9014)
* [AI] Write budget files atomically (temp file + rename)

/upload-user-file and loot-core's file writer both wrote directly to
their final path with a single fs.writeFile call. A write that fails
partway through (disk full, process killed, etc.) leaves the previous
good file truncated/corrupted, and any concurrent reader (the download
endpoint, or an external tool like backup software) can observe a torn
write mid-upload.

All three now write to a uniquely-named temp file and rename it over
the target, mirroring the pattern already used elsewhere in this repo
(cli/cache.ts, asyncStorage/index.electron.ts, desktop-electron/index.ts).
loot-core's electron and api platform implementations share the new
atomic-write helper to avoid duplicating the retry/cleanup logic.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Fix typecheck errors from the atomic-write consolidation

promiseRetry's callback inferred a Promise<T | void> return because the
catch branch returned retry()'s void result; explicit generic + a
trailing throw fixes the inference. writeFile's public signature
returns Promise<boolean>, so the thin wrappers need an explicit
`return undefined` now that there's no implicit fallthrough. Also
reverts an unnecessary narrowing of the mocked fs.promises.writeFile
callback param in app-sync.test.ts, which didn't match the real
PathLike | FileHandle signature.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Follow symlinks, keep file mode, and sweep orphaned temp files

Writes now resolve symlinks so the rename lands on the real file instead
of replacing the link, and carry the previous file's permission mode over
to the replacement. Before each write, temp files left for the same target
by a crashed process are removed; this process's own in-flight temp files
are skipped, assuming a single process owns the data directory.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Address review findings on atomic writes

- atomic-write.ts is a new file, so it is now type-strict.
- Preserving the file mode is best-effort: a filesystem that refuses chmod
  no longer fails the write. sync-server now preserves the mode too.
- The orphaned temp-file sweep runs once per directory per run and matches
  only our own temp names, so crash leftovers for files that are never
  rewritten (e.g. timestamped backups) are cleaned up without listing the
  directory on every write.
- A symlink to a missing file is followed instead of replaced.
- The real lock-retry behaviour is now tested (recover, and give up).
- Release note category is Bugfix, per the contributing docs.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Fix lock-retry tests hanging when file I/O is slow

settleWithFakeTimers stopped advancing fake time after 100 event-loop
turns. When real file I/O outlasted that budget (as on a loaded CI
runner), the next backoff timer was scheduled after the loop gave up and
never fired, so the test hung until its 5s timeout. Advance until the
write settles instead; a genuine hang still fails on the test timeout.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Guard user file paths against escaping the user files directory

getPathForUserFile now resolves the blob path and refuses anything that
lands outside the configured userFiles directory. Callers already
validate the id with isValidFileId; this makes the containment explicit
where the path is built, in a form CodeQL's path-injection query
recognizes as a sanitizer.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Follow symlinks for sync-server uploads via a shared atomic write helper

The upload route renamed its temp file over the blob path directly, so a
symlinked blob was replaced by a regular file and its real target left
stale. Before the atomic-write change, fs.writeFile followed the link.

Move the upload write into atomicWriteUserFile in util/paths.ts, which
resolves symlinks (like loot-core's atomicWriteFile), stages the temp
file next to the real target, sweeps that directory, preserves the mode
and renames into place. The route handler is back to a single call.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Flush atomic writes to disk and create temp files with the original mode

Write the temp file with flush: true so its data reaches disk before the
rename; otherwise a power loss can leave the target renamed but empty on
some filesystems.

Read the existing file's mode first and create the temp file with it,
instead of creating it with the default mode and chmod-ing afterwards.
The new contents are then never more readable than the file they
replace, even briefly or if chmod fails. The chmod stays (best-effort)
because the umask can strip bits at creation.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Type atomicWriteFile contents as string or binary

Callers already pass raw bytes (backup zips, db.sqlite from a backup
restore or cloud download); it only typechecked because the platform fs
files are ts-strict-ignore. Accept string | NodeJS.ArrayBufferView and
cover a byte-for-byte binary write.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Rename concurrent-write tests to match what they check

Both tests claimed to cover the sweep's in-flight guard, but the
directory is already swept by the time the nested write runs, so they
never reach it. What they do verify is that concurrent writes to one
target use distinct temp files and the last rename wins.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Clarify the atomic-write release note

Name the affected apps (the browser build is unchanged) and fix the
missing article.

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] Trim atomic-write tests to the essential cases

* [AI] Simplify atomic writes to temp file plus rename

* [AI] Keep dangling symlinks and exact file modes in atomic writes

Restore the user file path containment guard for CodeQL.

* [AI] Resolve dangling symlink targets through the filesystem

* [AI] Accept a filesystem root as the user files directory

* [AI] Fix root user files test cleanup typing

* [AI] Drop the redundant utf8 encoding option from atomicWriteFile

* [AI] Tighten atomic-write comments and release note

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Tim Smart <hello@timsmart.co>
2026-10-25 03:00:02 +00:00
Julian Dominguez-SchatzandGitHub 97a7ca50f3 [AI] Add per-budget SimpleFIN credentials (#9214)
* [AI] Add per-budget SimpleFIN credentials

* [AI] Clear budget credentials when switching SimpleFIN to global

* [AI] Reject SimpleFIN access to deleted budgets

* [AI] Use distinct keys in SimpleFIN isolation test
2026-10-23 12:46:49 +00:00
Matt FiddamanandGitHub d1a536f35c bump node and electron (#9298)
* bump node and electron

* use nvm node version in CI

* note

* bump docker node image
2026-10-21 23:30:46 +00:00
Julian Dominguez-SchatzandGitHub 0c571bc476 [AI] Block bank sync for deleted budgets (#9266)
* [AI] Block bank sync for deleted budgets

* Update bank sync handling for deleted budgets

* [AI] Make budget deletion and secret cleanup atomic
2026-10-21 18:59:22 +00:00
6e68ee1de1 [AI] Surface the real GoCardless error reason in the UI (#8778)
* [AI] Surface the real GoCardless error reason in the UI

When a GoCardless call failed, the reason was lost twice on the way to the
user. The sync server's `handleError` collapsed every failure into
`error_code: 'INTERNAL_ERROR'` plus the classified message, dropping the
`summary`/`detail` GoCardless itself returned; the bank-list modal then
ignored the payload entirely and rendered one hardcoded sentence blaming
misconfigured credentials. An IP block and a rate limit both surfaced as
"GoCardless access credentials might be misconfigured", leaving self-hosters
to guess without server logs.

Forward a whitelisted `error_details` (`status`, `summary`, `detail`) from
the server and render it in the modal, falling back to the existing generic
sentence when a failure carries no reason.

`error_code`/`error_type` keep their current meaning and values, since
`handleError` is shared by every GoCardless route and consumers branch on
specific codes. Only `summary`/`detail` travel — never the raw body or the
request headers, which carry the bearer token — and both are truncated so a
stray HTML error page cannot flood the UI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Address review: guard superseded bank-list requests

Ignore `gocardless-get-banks` responses for a country the user has
already moved on from, so a slow failing request cannot overwrite the
banks, error and loading state produced by the request that replaced it.

Also replace the `as never` cast in the /get-banks success test with the
shared `mockInstitution` fixture.

* [AI] Only surface error details from GoCardless responses

Drop the fallback that read summary/detail off any error's raw details, so text that did not come from a GoCardless API response is never echoed to the client.

---------

Co-authored-by: zannis <1011451+zannis@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-10-21 00:24:48 +00:00
spa77kandGitHub 7cd04aaf0d [AI] Fix newline conversion for HTTPS key and cert environment variables (#9265) 2026-10-20 23:55:53 +00:00
Julian Dominguez-SchatzandGitHub 7474a94299 [AI] Restrict SimpleFIN private network access to configured ranges (#9245) 2026-10-18 22:01:42 +00:00
Matt FiddamanandGitHub 63180ceeab ⬆️ october dependency bump (#9244)
* @types/node (^22.20.1 → ^22.20.5)

* eslint (^10.7.0 → ^10.12.0)

* eslint-plugin-perfectionist (^5.10.0 → ^5.12.1)

* knip (^6.27.0 → ^6.41.0)

* lage (^2.15.17 → ^2.17.0)

* minimatch (^10.2.5 → ^10.2.6)

* p-limit (^7.3.0 → ^7.3.3)

* vitest (^5.0.0 → ^5.0.4)

* uuid (^14.0.2 → ^14.0.3)

* rollup-plugin-visualizer (^7.0.1 → ^7.1.1)

* vite (^8.1.5 → ^8.3.4)

* @bufbuild/protobuf, @bufbuild/protoc-gen-es (^2.12.1 → ^2.16.0)

* @chromatic-com/storybook (^5.2.1 → ^5.5.1), @storybook/addon-a11y, @storybook/addon-docs, @storybook/react-vite, eslint-plugin-storybook, storybook (^10.5.2 → ^10.6.2)

* fix tests

* @internationalized/date (^3.12.2 → ^3.12.4), react-aria-components (^1.19.0 → ^1.22.1), react-aria (^3.50.0 → ^3.53.1)

* @rolldown/plugin-babel (~0.2.3 → ~0.2.4)

* @testing-library/react (16.3.2 → 16.3.3), @testing-library/dom (10.4.1 → 10.4.2), @testing-library/user-event (14.6.1 → 14.6.8)

* @types/react (^19.2.17 → ^19.3.0), @types/react-dom (^19.2.3 → ^19.3.0)

* @vitejs/plugin-react (^6.0.3 → ^6.1.2)

* react, react-dom (19.2.7 → 19.3.0)

* @babel/core (^8.0.1 → ^8.0.7)

* @codemirror/language (^6.12.4 → ^6.13.1), @codemirror/state (^6.7.1 → ^6.7.6), @codemirror/view (^6.43.6 → ^6.43.14), @lezer/highlight (^1.2.3 → ^1.2.5), @uiw/react-codemirror (^4.25.11 → ^4.25.12)

* @fontsource-variable/inter, @fontsource/redacted-script (^5.2.8 → ^5.3.0)

* @reduxjs/toolkit (^2.12.0 → ^2.13.0)

* @tanstack/react-query (^5.101.2 → ^5.104.2)

* csv-stringify (^6.8.1 → ^6.9.0)

* es-toolkit (^1.49.0 → ^1.52.0)

* hyperformula (^3.3.0 → ^3.5.0)

* i18next (^26.3.6 → ^26.4.4)

* i18next-resources-to-backend (^1.2.1 → ^1.2.3)

* lru-cache (^11.5.2 → ^11.5.3)

* react-error-boundary (^6.1.2 → ^6.1.6)

* react-grid-layout (^2.2.3 → ^2.3.0)

* react-i18next (^17.0.10 → ^17.0.16)

* react-router (8.3.0 → 8.4.0)

* recharts (^3.9.2 → ^3.10.1)

* rolldown (^1.2.0 → ^1.2.13)

* sass (^1.101.0 → ^1.105.1)

* @easyops-cn/docusaurus-search-local (^0.55.2 → ^0.55.3)

* @r74tech/docusaurus-plugin-panzoom (^2.4.2 → ^2.5.0)

* eslint-vitest-rule-tester (^3.1.0 → ^3.2.0)

* csv-parse (^7.0.2 → ^7.0.3)

* fast-check (^4.9.0 → ^4.10.2)

* jest-diff (^30.4.1 → ^30.5.2)

* yargs (^18.0.0 → ^18.2.0)

* @capacitor/android (^8.4.3 → ^8.5.3), @capacitor/core, @capacitor/cli (^8.4.2 → ^8.5.3)

* express (^5.2.1 → ^5.3.0)

* express-rate-limit (^8.6.0 → ^8.7.1)

* ipaddr.js (^2.4.0 → ^2.5.0)

* supertest (^7.2.2 → ^7.3.1)

* oxlint, @oxlint/plugins (^1.74.0 → ^1.88.0), oxlint-tsgolint (^0.25.0 → ^7.0.2004)

* oxfmt (^0.59.0 → ^0.73.0)

* cosmiconfig (^9.0.2 → ^10.0.1)

* @testing-library/jest-dom (^6.9.1 → ^7.0.1)

* jsdom (^29.1.1 → ^30.1.2)

* vite-plugin-pwa (^1.3.0 → ^2.0.0)

* argon2 (^0.44.0 → ^0.45.1)

* pluggy-sdk (^0.89.0 → ^0.92.0)

* note

* bump crdt

* Revert "@capacitor/android (^8.4.3 → ^8.5.3), @capacitor/core, @capacitor/cli (^8.4.2 → ^8.5.3)"
2026-10-17 02:02:36 +00:00
ANURAG VERMAandGitHub af7c06fcb3 [AI] Fix Enable Banking counterparty selection by payment direction (#9204)
* [AI] Fix Enable Banking counterparty selection by payment direction

* [AI] Add release note for Enable Banking counterparty fix
2026-10-16 23:52:10 +00:00
Julian Dominguez-SchatzandGitHub 42e9d79d4a Merge commit from fork
* [AI] Reject invalid password inputs before hashing

- Require non-empty strings at password validation, hashing and verification
  boundaries so JSON objects, arrays and other scalar types cannot reach
  Argon2's buffer conversion.
- Add regressions for malformed passwords on fresh and configured servers,
  including assertions that rejected input never reaches Argon2.

Advisory:
https://github.com/actualbudget/actual/security/advisories/GHSA-3jjw-2hq7-mmm2

* [AI] Require admin permission for EnableBanking configuration

- Require administrator permission to configure EnableBanking, even when
  credentials have not been configured yet.
- Check permission before validating credentials with the provider or
  persisting secrets, and disable configuration controls for non-admins.
- Test unauthenticated, BASIC and ADMIN requests against empty and existing
  configuration, preserving secrets and avoiding provider calls on denial.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-hfxx-qc34-gqcw

* [AI] Neutralize BOM-prefixed CSV formulas

- Detect spreadsheet formula triggers after leading BOM characters and
  prepend an apostrophe before the original text.
- Protect textual CSV headers and scalar values as well as ordinary strings.
- Preserve numeric output, including negative amounts, and cover repeated
  BOMs, formula triggers, quoting and Unicode text in regression tests.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-7jvc-qfpw-85g2

* [AI] Remove ambiguous Commerzbank payee matching

- Split Commerzbank payees into non-empty whitespace/slash-delimited tokens
  and escape their literal text before constructing the cleanup expression.
- Use consuming separators that cannot overlap the literal tokens, avoiding
  ambiguous matching on long runs of spaces or slashes.
- Require separators between payee tokens: concatenated words in notes are
  no longer stripped. Allow 20 seconds for the hostile-case subprocess,
  including Node and Vite startup on slower CI runners.
- Skip matching for empty payees while preserving normal note cleanup.
- Exercise hostile payees, including the report's spaced-word reproducer,
  in a subprocess with a hard timeout; retain the existing bank fixtures.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-p34v-m2gp-w3jm

* [AI] Reject unsafe IPv6 address classes in SSRF checks

- Allow public unicast addresses by default. The private-network option
  additionally permits private, loopback, unique-local and carrier-grade NAT addresses.
- Permit the well-known NAT64 prefix only for embedded public IPv4
  destinations; private and metadata addresses remain blocked in both modes.
- Reject other IPv6 transition, multicast, reserved and link-local classes in
  both modes, and classify IPv4-mapped addresses by the embedded IPv4 address.
- Cover literal URLs, DNS answers, redirects and both SimpleFIN fetch paths,
  including NAT64, 6to4 and Teredo addresses, with synthetic upstreams.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-97j5-6g5r-42v5

* [AI] Exclude callback secrets from ordinary server logs

- Log request method, pathname and response status without query strings,
  and restrict serialized metadata to the same safe fields.
- Keep full OpenID and banking provider messages, response bodies, session
  identifiers and error stacks behind existing actual-sensitive namespaces.
- Apply the same opt-in handling to shared banking errors, proxy target
  URLs and unhandled rejections; do not forward raw streaming errors to
  Express's ordinary error logger.
- Stop logging stored secret values, including with debugging enabled.
- Document targeted sensitive debugging and private support exchanges.
- Test ordinary and opt-in output, query and serialized metadata leaks,
  provider failures, session URLs, streaming errors and secret storage.

- Preserve provider format sequences by passing SimpleFIN response text as
  a debug format argument, rather than part of the format string.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-ppcp-hx2h-fm35

* [AI] Revoke password sessions when credentials change

- Update the password hash and revoke all password-authenticated sessions
  in one transaction, including password changes through the local CLI.
- Issue a fresh token for each successful password login instead of reusing
  an existing session token.
- Recheck the verified password hash before creating a session so an
  in-flight login cannot restore access after a credential change.
- Correct the UI's claim that other sessions remain signed in, and test
  multiple sessions, CLI resets, transaction rollback and login/reset races.

This addresses session revocation and token reuse. Requiring the current
password for remote changes is covered by the following commit.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-7363-3qq5-2frj
https://github.com/actualbudget/actual/security/advisories/GHSA-4wgp-48c6-v9w3

* [AI] Require the current password for remote password changes

- Require currentPassword alongside the replacement password for remote
  changes, preserving the administrator and password-authentication checks.
- Verify the current credential, rate-limit attempts and reject a change
  if the verified password hash changes before the update.
- Collect the current password in the client and handle failure to sign in
  after a successful change. Keep the local reset command available without
  the old password.
- Test that a session token alone cannot change credentials and that failed
  requests preserve the existing password and sessions.

- Clear the redundant success notice when signing in with the new password fails.

Advisories:
https://github.com/actualbudget/actual/security/advisories/GHSA-4wgp-48c6-v9w3

* [AI] Restrict Electron protocol launches and network file reveals

- Allow only parsed HTTP/HTTPS URLs through external-opening IPC,
  new-window handling and navigation, addressing GHSA-7pf2-w24j-p6h2.
- Also reject network/UNC paths in the separate file-reveal handler.
  A note such as [View receipt](//host/share/invoice.pdf) reaches
  showItemInFolder without passing through openExternal. On Windows,
  resolving that share can disclose NTLM authentication responses to an
  attacker-controlled server where network and authentication policies
  permit it. This additional flow was not demonstrated in the advisory.
- Accept native absolute local paths without adding file-URL conversion.
- Test protocol filtering and network-path rejection without invoking OS
  handlers. The note-to-file-reveal flow is code-confirmed; an actual
  Windows authentication exchange has not been reproduced.

The following commit addresses the advisory's separate internal-origin
classification finding.

Advisory:
https://github.com/actualbudget/actual/security/advisories/GHSA-7pf2-w24j-p6h2

Additional finding references:
https://github.com/electron/electron/blob/v43.4.0/shell/common/platform_util_win.cc#L270-L340
https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-ntlm-blocking

- Exercise Windows path semantics on all test platforms and exclude generated
  Electron tests and Vitest configuration from the packaged application.

* [AI] Classify Electron app URLs exactly and block redirects

- Replace substring checks with exact app://actual scheme/host matching
  and the existing development origin, http://localhost:3001.
- Use the classification for browser handoffs and focus/log script
  execution so remote URLs containing app:// or localhost: are not
  mistaken for app pages.
- Preserve the existing global renderer-navigation block and add redirect
  blocking there, without duplicating it in the main-window handlers.
- Keep ordinary IPC registration unchanged; broad sender validation is
  outside this URL-classification fix.
- Test misleading hosts, ports and URL substrings. Exercise ordinary
  clicks, new-window links and explicit browser IPC in Electron, asserting
  the exact HTTP/HTTPS URLs handed to the browser without opening real
  OS handlers. Exercise a local HTTP redirect to check the app stays put.

Advisory:
https://github.com/actualbudget/actual/security/advisories/GHSA-7pf2-w24j-p6h2

- Retain startup logs until an internal page finishes loading, then forward
  them to DevTools; cover startup delivery in the Electron navigation suite.

* [AI] Choose import destinations from trusted local context

- Allocate fresh local IDs for cloud downloads and local archive imports,
  ignoring destination IDs supplied in archived metadata.
- Pass an explicit local destination for replacement downloads and verify
  its cloud-file association. Do not require matching sync group IDs, so
  downloading the reset version of the same cloud file remains possible.
- Reject server metadata describing a different cloud file and close the
  budget before an authorized replacement.
- Retain existing import metadata compatibility, collision error handling,
  nested archive layouts and backups; do not require a budget name.
- Test targeted collisions, local recovery imports with obsolete IDs or
  missing optional metadata, mismatched cloud associations and replacement
  after a sync ID reset using real local files and databases.

Advisory:
https://github.com/actualbudget/actual/security/advisories/GHSA-7fr5-fjj8-hwjq

- Reuse the matching local budget for API downloads after a sync reset,
  report cloud-file mismatches in API/CLI errors, and document local IDs.

* [AI] Revoke sessions on sign-out and API shutdown

Revoke only the supplied session on explicit sign-out. Clear local credentials if the server cannot be reached, and revoke password-created API sessions during shutdown without revoking caller-supplied tokens.

Cover isolated and repeated revocation, invalid tokens, offline sign-out, borrowed API tokens and shutdown after a close failure. Session expiry policy is unchanged.

Follow-up to:
https://github.com/actualbudget/actual/security/advisories/GHSA-7363-3qq5-2frj
2026-10-08 08:34:05 -04:00
Harshil PatelandGitHub 1eeffe3278 [AI] Show clear error and configure action when GoCardless credentials are missing (#8963)
* [AI] Show clear error and configure action when GoCardless credentials are missing

* [AI] Restore GoCardless transaction handler after test

* [AI] Persist not-configured sync status and hide configure action for non-admins
2026-10-04 11:43:41 +00:00
Matt FiddamanandGitHub 18e995513b add retry when GoCardless access token exires (#9088)
* add requisitions retry

* note
2026-10-04 09:13:15 +00:00
cakallieGitHubCarstenautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>Claude Sonnet 4.6
821caa2643 [AI] fix(enablebanking): fix HypoVereinsbank auth and data access (#8355)
* fix(enablebanking): pass PSU IP address header for HypoVereinsbank auth

HypoVereinsbank falls back to corporate auth portal when psu-ip-address
header is missing, because the first auth_method is "business". Passing
the PSU headers from the incoming request selects the personal banking
method instead.

* fix(enablebanking): remove PSU headers from data access calls

HypoVereinsbank requires Psu-Ip-Address during authorization to select
the personal auth method, but rejects it on balance/transaction API
calls with ASPSP_ERROR. Restrict PSU headers to startAuth only.

Also add balances/transactions consent scopes to the auth request
as required by the Enable Banking API.

* [AI] chore: add release notes for #8355

* [autofix.ci] apply automated fixes

* Scope PSU header removal to HypoVereinsbank only for data access calls

Instead of stripping PSU headers globally from balance/transaction fetches,
introduce `ASPSPS_WITHOUT_DATA_ACCESS_PSU_HEADERS` and `dataAccessPsuHeaders()`
so only ASPSPs known to reject these headers are affected. Other ASPSPs continue
to receive PSU headers on data access calls.

Also restore PSU headers being passed through `buildSessionResult()` at both
the auth_callback and poll-auth call sites, and propagate `aspspName` from the
client via the `/transactions` endpoint so the scoping helper has the context
it needs to decide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [autofix.ci] apply automated fixes

* Fix dataAccessPsuHeaders to pass through headers when aspspName is unknown

The previous condition `!aspspName || set.has(aspspName)` stripped PSU headers
whenever aspspName was undefined, breaking all ASPSPs that don't send it.
The correct default is to pass headers through for unknown ASPSPs and only
strip them when the ASPSP is explicitly listed in the exclusion set.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Carsten <carsten@kallies-net.de>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-03 12:01:47 +00:00
Guo-YixinandGitHub 2dc69b3de5 [AI] fix(sync-server): prevent duplicate Enable Banking transactions (#9046) 2026-10-02 18:06:24 +00:00
github-actions[bot]GitHubgithub-merge-queuegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Matt Fiddamanautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
3a77479e14 🔖 (26.10.0) (#9011)
* 🔖 (26.10.0)

* Generate release notes for v26.10.0

* add frontmatter

* [autofix.ci] apply automated fixes

* Generate release notes for v26.10.0

* Generate release notes for v26.10.0

* link to experimental sidebar docs

* [autofix.ci] apply automated fixes

* cleanup from cherrypicks

* Generate release notes for v26.10.0

* cleanup cp notes

* update release date

* [autofix.ci] apply automated fixes

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-10-02 15:23:08 +00:00
Mohammed Yasin ZuhayrandGitHub 967684afa4 chore: migrate sync-server app-sync validation and errors to TypeScript (#9030)
* chore: migrate sync-server app-sync validation and errors to TypeScript

* fix: reject an empty x-actual-group-id header on upload
2026-09-29 00:51:16 +00:00
954f970241 [AI] Migrate create-folders migration to TypeScript (#8851)
* [AI] Migrate create-folders migration to TypeScript

* [AI] Add release note for create-folders migration

* [AI] Preserve migration titles after TypeScript conversion

* [AI] Reject duplicate normalized migration titles

---------

Co-authored-by: Baris Arı <226740765+rapsoidmorningstar@users.noreply.github.com>
Co-authored-by: Baris Ari <226740765+barislabs@users.noreply.github.com>
2026-09-23 07:53:19 +00:00
Matt FiddamanandGitHub 8f2318d1dc ⬆️ better-sqlite3 v13 (#8736)
* better-sqlite3 v13

* note

* fix build

* engine update

* fix yarn warning and arm32 docker builds
2026-09-20 20:22:32 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>MatissJanisClaude Opus 5
d5d0b663c9 Bump @vitest/mocker from 4.1.10 to 5.0.0 in the npm_and_yarn group across 0 directory (#8923)
* Bump @vitest/mocker in the npm_and_yarn group across 0 directory



Updates `@vitest/mocker` from 4.1.10 to 5.0.0
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v5.0.0/packages/mocker)

---
updated-dependencies:
- dependency-name: "@vitest/mocker"
  dependency-version: 5.0.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

* [AI] Fix typecheck failures under vitest 5

Vitest 5 changed two things that broke the typecheck/build jobs:

- `vi.fn()`'s inferred type now references `Procedure` from an internal
  vitest chunk that cannot be named from outside, so the hoisted mocks in
  `cloud-storage.test.ts` tripped TS2883. Annotate them as `Mock`.
- The `expect` package was inlined and the global `jest.Matchers`
  declaration dropped, so `@testing-library/jest-dom`'s default entry no
  longer augments vitest's `Assertion`. Use the `/vitest` entry point
  instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc

* [AI] Bump @actual-app/crdt to 3.1.3

The dependency bump touches packages/crdt/package.json, so the CRDT
version bump check requires a new version. Matches how the previous
dependabot group bump (#8921) was handled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc

* [AI] Add release note for the vitest bump

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bvwt76cXUoLwfHiy1jhToc

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: MatissJanis <matiss@mja.lv>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 18:38:38 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Matiss Janis Aboltins
5c76dfbd92 Bump the npm_and_yarn group across 1 directory with 5 updates (#8921)
* Bump the npm_and_yarn group across 1 directory with 5 updates

Bumps the npm_and_yarn group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [csv-parse](https://github.com/adaltas/node-csv/tree/HEAD/packages/csv-parse) | `7.0.1` | `7.0.2` |
| [colord](https://github.com/omgovich/colord) | `2.9.3` | `2.10.0` |
| [joi](https://github.com/hapijs/joi) | `17.13.4` | `17.13.7` |
| [smol-toml](https://github.com/squirrelchat/smol-toml) | `1.6.1` | `1.8.0` |
| [svgo](https://github.com/svg/svgo) | `3.3.4` | `3.3.5` |



Updates `csv-parse` from 7.0.1 to 7.0.2
- [Changelog](https://github.com/adaltas/node-csv/blob/master/packages/csv-parse/CHANGELOG.md)
- [Commits](https://github.com/adaltas/node-csv/commits/csv-parse@7.0.2/packages/csv-parse)

Updates `colord` from 2.9.3 to 2.10.0
- [Release notes](https://github.com/omgovich/colord/releases)
- [Changelog](https://github.com/omgovich/colord/blob/master/CHANGELOG.md)
- [Commits](https://github.com/omgovich/colord/commits/v2.10)

Updates `joi` from 17.13.4 to 17.13.7
- [Commits](https://github.com/hapijs/joi/compare/v17.13.4...v17.13.7)

Updates `smol-toml` from 1.6.1 to 1.8.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.8.0)

Updates `svgo` from 3.3.4 to 3.3.5
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v3.3.4...v3.3.5)

---
updated-dependencies:
- dependency-name: csv-parse
  dependency-version: 7.0.2
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: colord
  dependency-version: 2.10.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: joi
  dependency-version: 17.13.7
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: smol-toml
  dependency-version: 1.8.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: svgo
  dependency-version: 3.3.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>

* Bump version from 3.1.1 to 3.1.2

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2026-09-10 22:23:04 +00:00
1dcf7aaa71 [AI] Support reading secrets from a file with a _FILE environment variable (#8868)
* [AI] Support reading any setting from a file with a _FILE environment variable

Adds the `_FILE` environment-variable suffix convention used by Docker
secrets and Kubernetes file-mounted secrets. Setting `<VAR>_FILE` to a path
makes Actual read that setting's value from the file, so secrets can be
mounted rather than passed through the environment.

This covers both config systems: every env-backed setting in the sync
server's convict schema, and every env-backed setting in the CLI.

On the sync-server side the override is applied after `loadFile()` and
before `validate()`, using `set()`. convict re-imports the environment at
the end of both `load()` and `loadFile()`, so an override applied any
earlier would be clobbered by the plain environment variable.

A `_FILE` variable pointing at an unreadable file is a hard error rather
than a silent fallback, so a secret that failed to mount stops startup
instead of leaving the server running with an empty value.

Refs #5233, #7686. Supersedes the approach in #5235, which applied the
override before `loadFile()` and so had the precedence backwards.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Address review feedback on _FILE support

- Treat a `_FILE` variable that is set but empty as an unreadable path rather
  than as unset. Previously it fell back to the plain environment variable,
  which contradicted the documented behaviour and hid a failed mount. This
  applied to both the CLI and the sync server; regression tests added for both.
- Read `_FILE` variables by their literal name in the CLI's resolution chain,
  so the `_FILE` variables are greppable in the config module and the
  precedence order is visible in the chain itself. This also keeps `utils.ts`
  free of filesystem access.
- List the remaining supported variables in the CLI environment variable table.
- Rename a test to describe what it asserts.
- Narrow the release note, which overstated the scope: `_FILE` applies to
  settings that already have an environment variable binding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Limit _FILE support to secrets

Following the convention set by Docker's official images, where only secrets
get a _FILE variant, this narrows the scope to:

- sync server: ACTUAL_OPENID_CLIENT_SECRET, ACTUAL_GITHUB_TOKEN
- CLI: ACTUAL_PASSWORD, ACTUAL_SESSION_TOKEN, ACTUAL_ENCRYPTION_PASSWORD

ACTUAL_HTTPS_KEY and ACTUAL_HTTPS_CERT already accept a path, so they get no
_FILE variant.

Both sides now name the `_FILE` variables literally at the point of use, so
they are greppable and the precedence order is visible in the call itself.
On the sync server this replaces the generic schema walk, which had to mirror
convict's internal rule for telling a setting from a group; the schema no
longer has to be hoisted to a named const, so load-config.js is reduced to an
import and the override loop.

Also documents ACTUAL_ENCRYPTION_PASSWORD, which the CLI supports but neither
environment variable table listed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Use a descriptive name for the temp directory in the config file env tests

Addresses the remaining review nitpick: `dir` did not say what the directory
held. Renamed in both test files for consistency.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Trim comments and documentation per review

- Shorten the readFileEnv doc comments in both packages, and drop the note in
  load-config.js about which variables are deliberately excluded, keeping the
  two lines explaining why the override runs between loadFile and validate.
- Reduce the server documentation to a short note and move it to the top of
  the page.
- Point at the runtime's own secret support (e.g. Docker secrets) in the CLI
  security notes rather than suggesting a hand-made file.
- Drop the per-variable OpenID section, which repeated the note above it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* [AI] Simplify the wording of the _FILE precedence note

Replaces the sentence in the server docs, the CLI docs and the CLI README with
a shorter statement of precedence, and drops the note about stopping on an
unreadable file, which can be inferred.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-09-07 00:19:26 +00:00
github-actions[bot]GitHubgithub-merge-queuegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Tim SmartJulian Dominguez-Schatz
d05aa0f11a 🔖 (26.9.0) (#8789)
* 🔖 (26.9.0)

* Generate release notes for v26.9.0

* add release notes for 26.9.0

* tweak wording

* Generate release notes for v26.9.0

* Generate release notes for v26.9.0

* wording tweaks

* [AI] Add Tim Smart to blog authors

* update authors

* Use relative doc links in 26.9.0 release notes

* Update packages/docs/blog/2026-09-01-release-26-9-0.md

Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>

* tweak schedule button

* fix links

* Apply suggestion from @jfdoming

Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tim Smart <hello@timsmart.co>
Co-authored-by: Julian Dominguez-Schatz <julian.dominguezschatz@gmail.com>
2026-09-01 02:30:38 +00:00
ShahidandGitHub baba5f502c Change title util to TypeScript (#8553)
* Migrate title util to TypeScript

* Add release notes

* Type the options parameter to preserve custom specials

* Move title options type inline
2026-08-22 23:26:37 +00:00
AnjuandGitHub 3ac0d7309b [AI] Migrate health-check script to TypeScript (#8599)
* [AI] Migrate health-check script to TypeScript

* [AI] Include TypeScript scripts in knip entries

* [AI] Validate health status response type
2026-08-22 22:32:16 +00:00
faadbb37bb GoCardless: derive Alior payee from the card transaction description (#8738)
* GoCardless: derive Alior payee from the card transaction description

Alior Bank stopped returning creditorName on outgoing transactions in
early July 2026. Without it, formatPayeeName falls through to debtorName,
which on an outgoing transaction is the account holder, so every card
payment is booked against the user instead of the merchant.

The merchant is still available behind a fixed prefix in
remittanceInformationUnstructured, so take it from there when creditorName
is missing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* rename release note to the PR number

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 13:29:09 +00:00
Gautam SinghandGitHub 19ae5da8b5 Return an error when changing password with no password method (#8603)
* Return an error when changing password with no password method

changePassword ran an UPDATE against method = 'password' and returned success even when it matched zero rows. On an instance configured with only openid auth, the reset-password script therefore reported success without saving a password.

* Add release note
2026-08-11 12:26:27 +00:00
ecf069d35b 🔖 (26.8.1) (#8671)
* 🔖 (26.8.1)

* generate release notes

* add header

* add account context note

* change date

---------

Co-authored-by: matt-fidd <81489167+matt-fidd@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-08-07 21:02:23 +00:00
github-actions[bot]GitHubgithub-merge-queuegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github-actions[bot] <matiss@mja.lv>Claude Fable 5
011b49e550 🔖 (26.8.0) (#8563)
* 🔖 (26.8.0)

* Generate release notes for v26.8.0

* Add release notes for version 26.8.0, highlighting new stable features, mobile banking improvements, and day-level date range selection in reports.

* Update authorship in release notes for version 26.8.0 to reflect MatissJanis as the author.

* [AI] Apply review feedback to 26.8.0 release notes: clarify onboarding/mobile bank sync wording and note per-file credentials are Pluggy.ai only

* [AI] Copy review-feedback wording fixes into releases.md for 26.8.0

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <matiss@mja.lv>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-02 20:20:21 +00:00
Julian Dominguez-SchatzandGitHub fd4dea21ae Update to Node 24 (#8604) 2026-08-02 16:00:07 +00:00
Matt FiddamanandGitHub cefd52e9c3 better simplefin errors (#8568)
* better simplefin errors

* note

* coderabbit
2026-07-27 15:55:22 +00:00
Matt FiddamanGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>Matiss Janis Aboltins
ff1b6045a1 ⬆️ mid month dependency update (#8533)
* @types/node (^22.19.21 → ^22.20.1)

* eslint (^10.5.0 → ^10.7.0)

* eslint-plugin-perfectionist (^5.9.0 → ^5.10.0)

* knip (^6.17.1 → ^6.27.0)

* lage (^2.15.13 → ^2.15.17)

* vitest (^4.1.8 → ^4.1.10)

* better-sqlite3 (^12.10.0 → ^12.11.1)

* vite (^8.0.16 → ^8.1.5)

* react-aria-components (^1.18.0 → ^1.19.0)

* @storybook/addon-a11y (^10.4.4 → ^10.5.2)

* @storybook/addon-docs (^10.4.4 → ^10.5.2)

* @storybook/react-vite (^10.4.4 → ^10.5.2)

* @vitejs/plugin-react (^6.0.2 → ^6.0.3)

* eslint-plugin-storybook (^10.4.4 → ^10.5.2)

* storybook (^10.4.4 → ^10.5.2)

* @bufbuild/protobuf (^2.12.0 → ^2.12.1)

* @bufbuild/protoc-gen-es (^2.12.0 → ^2.12.1)

* @codemirror/language (^6.12.3 → ^6.12.4)

* @uiw/react-codemirror (^4.25.10 → ^4.25.11)

* csv-stringify (^6.7.0 → ^6.8.1)

* es-toolkit (^1.47.1 → ^1.49.0)

* i18next (^26.3.1 → ^26.3.6)

* lru-cache (^11.5.1 → ^11.5.2)

* react-aria (^3.49.0 → ^3.50.0)

* react-hotkeys-hook (^5.3.2 → ^5.3.3)

* react-i18next (^17.0.8 → ^17.0.10)

* rolldown (^1.1.1 → ^1.2.0)

* @docusaurus/core (^3.10.1 → ^3.10.2)

* @docusaurus/plugin-content-docs (^3.10.1 → ^3.10.2)

* @docusaurus/plugin-ideal-image (^3.10.1 → ^3.10.2)

* @docusaurus/preset-classic (^3.10.1 → ^3.10.2)

* @docusaurus/theme-common (^3.10.1 → ^3.10.2)

* @docusaurus/theme-mermaid (^3.10.1 → ^3.10.2)

* unist-util-visit-parents (^6.0.0 → ^6.0.2)

* @docusaurus/module-type-aliases (^3.10.1 → ^3.10.2)

* @docusaurus/types (^3.10.1 → ^3.10.2)

* @oxlint/plugins (^1.69.0 → ^1.74.0)

* @types/estree (^1.0.8 → ^1.0.9)

* fast-check (^4.8.0 → ^4.9.0)

* @capacitor/android (^8.0.0 → ^8.4.2)

* @capacitor/core (^8.0.0 → ^8.4.2)

* @capacitor/ios (^8.0.0 → ^8.4.2)

* @capacitor/splash-screen (^8.0.1 → ^8.0.2)

* @capgo/capacitor-updater (^8.50.1 → ^8.51.2)

* @capacitor/cli (^8.0.0 → ^8.4.2)

* @capgo/cli (^8.22.0 → ^8.28.2)

* express-rate-limit (^8.5.2 → ^8.6.0)

* @types/supertest (^7.2.0 → ^7.2.1)

* http-proxy-middleware (^4.1.1 → ^4.2.0)

* oxlint (^1.69.0 → ^1.74.0) & oxlint-tsgolint (^0.23.0 → ^0.25.0)

* @codemirror/state (^6.6.0 → ^6.7.1) & @codemirror/view (^6.43.1 → ^6.43.6)

* @tanstack/react-query (^5.101.0 → ^5.101.2)

* recharts (^3.8.1 → ^3.9.2)

* note

* oxfmt (^0.44.0 → ^0.59.0)

* @babel/core (^7.29.7 → ^8.0.1)

* downshift (9.3.6 → 9.4.0)

* react-router (7.17.0 → 8.2.0)

* csv-parse (^6.2.1 → ^7.0.1)

* pluggy-sdk (^0.85.3 → ^0.89.0)

* yarn (4.13.0 -> 4.17.1)

* yarn dedupe

* Update VRT screenshots

Auto-generated by VRT workflow

PR: #8533

* crdt version bump

* [autofix.ci] apply automated fixes

* Update packageManager version to yarn@4.17.1

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
2026-07-21 20:24:31 +00:00
NustinuaGitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
a29d9d81b5 Skip Enable Banking PSU headers for local IPs (#8032)
* Skip Enable Banking PSU headers for local IPs

* Add release note for Enable Banking PSU headers

* Include IPv4 link-local addresses in PSU header filter

* Use trusted proxy resolved IP for Enable Banking PSU headers

* Avoid logging Enable Banking PSU header values

* Use shared SSRF helper for Enable Banking PSU headers

* Fix space

* Add shared SSRF helper for Enable Banking PSU headers

* Use public IP in Enable Banking PSU header test

* [autofix.ci] apply automated fixes

* Add tests for shared SSRF helper

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-21 19:47:58 +00:00
a31cfe7514 fix electron GoCardless linking (#8510)
* fix electron invalid origin

* [AI] Add tests for the desktop GoCardless linking fix

Covers the electron fetch wrapper's derived Origin header and the
sync-server /gocardless/create-web-token origin and id validation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TKqNWc6Lbigv8e61uLoopU

* note

* allow old origin and move link so that it exists on electron bundled server

* provide a valid redirect URL to GoCardless

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 07:52:35 +00:00
lelemmGitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
4556e9e244 🐛 Prevent Pluggy bank sync from repeatedly rewriting transactions (#8392)
* Prevent Pluggy bank sync from repeatedly rewriting uncategorized and transfer transactions

* Regression test

* Changed solution for the fix

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-08 19:33:28 +00:00
lelemmGitHubautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
744dd1eaff Bank Sync Provider per budget file [2/3] - Sync server - Pluggy.ai use per-budget credentials when available (#8317)
* PR for pluggy ai wiring per file budget ni pluggy

* Fixes from rebase

* Code rabbit code review

* [autofix.ci] apply automated fixes

* added md

* Restoring client cache

* code review

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-07-04 19:10:51 +00:00
Matt FiddamanandGitHub 73c1fb19e9 recognise EUA expired GoCardless responses (#8383)
* recognise EUA expired GoCardless responses

* note

* add test
2026-07-04 13:08:32 +00:00
+4
lelemmGitHubMatt FiddamantabedzkiClaude Sonnet 4.6youngcwMatt Farrellcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>Dustin BrewerMatiss Janis Aboltinsautofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>Alec BakholdinclintharrisDarwin Do
b054e9a013 Bank Sync Provider per budget file [1/3] - Sync server - Add file-scoped bank sync secrets (#8316)
* First PR for secrets per file

* md

* Code Review

* Code rabbit code review

* Removed migration (new column) in favor of string concatenation

* automation UI: reference schedule by ID not name (#8308)

* schedule by id

* migrate schedule indicators

* add tests

* update release note

* fix loading states

* [AI] feat(budget analysis report): Add Balance & Category selector (#8162)

* [AI] feat(budget-report): add balance-only view mode

Add a 'Balance only' toggle to the Budget Analysis report that hides the
Budgeted, Spent, and Overspending Adjustment series and renders the balance
as a plain line chart, similar to the Net Worth graph.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] fix(budget-report): always display ending balance for consistent header spacing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] feat(budget-report): replace balance toggle buttons with series dropdown

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] fix(budget-report): capitalize Categories in balance mode dropdown

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] fix(budget-report): fix test imports and lint errors in BudgetAnalysisGraph test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: added in release note

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] Fix Age of Money report widget title not saving correctly (#8320)

* [AI] Fix Age of Money report widget title not saving correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] Use mutateAsync to properly await mutations in AgeOfMoney widget

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix flaky vrt by increasing timeout (#8323)

* fix test

* note

* Update docs with Actuali iOS app (#8324)

* Update docs with Actuali iOS app

* Update packages/docs/docs/community-repos.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Initial payee location documentation (#8241)

* Initial payee location documentation

* Move to dedicated experimental section

Based on PR feedback

* [AI] feat(budget analysis report): show hidden categories (#8164)

* [AI] feat(budget-report): add toggle to include hidden categories

Add a 'Show hidden categories' button that includes hidden expense
categories in the Budget Analysis report. This prevents historic data
from being misrepresented when a category (e.g. a car fund) is hidden.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] feat(budget-report): replace hidden categories button with icon toggle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* [AI] fix(budget-analysis): use correct package alias in test import

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: added in release note

* [AI] refactor(budget-analysis): extract isBaseCategory helper and reuse in tests

Assisted-by: ClaudeCode:claude-sonnet-4-6

* [AI] feat(budget-report): clarify hidden categories toggle state

Replace the ambiguous icon-only toggle with a highlighted active state
and explicit click-to-show/hide tooltip text so the current selection is
clear. Add aria-pressed for accessibility.

Assisted-by: ClaudeCode:claude-opus-4.8

* [AI] feat(budget-report): consolidate chart options into Options dropdown menu

Replace the separate chart-type icon toggle, balance/category Select dropdown,
and hidden-categories eye icon with a single Options popover (Popover + Menu)
matching the pattern used by other reports (Sankey). The menu contains:
- Switch to line/bar chart
- Show balance (toggle)
- Show categories (toggle, replaces balanceOnly)
- Show hidden categories (toggle)

Also rebases onto upstream/master to incorporate the balanceOnly/Select
changes from #8162 before consolidating them.

Assisted-by: ClaudeCode:claude-sonnet-4-6

* [AI] fix(budget-report): use static 'Bar chart' toggle in Options menu for i18n

Replace the dynamic 'Switch to line/bar chart' string with a static
'Bar chart' label and a boolean toggle (on = bar, off = line), matching
the toggle pattern used by other menu items and making the string
straightforward to translate.

Assisted-by: ClaudeCode:claude-sonnet-4-6

* Enhance budget analysis report with dropdown options

Introduced a dropdown to group options and added the ability to show hidden categories in the budget analysis report.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* update release process (#8334)

* [AI] Add cross-platform hook adding 🤖 emoji to comments (#8331)

* [AI] Add cross-platform hook keeping GitHub comments/issues in Chinese or pirate voice

Adds a shared agent hook that requires anything an agent posts to GitHub
(PR/issue comments, PR reviews, created issues) to be written in 简体中文
(preferred) or, failing that, a fun pirate voice — never plain English.

- scripts/agent-hooks/github-comment-style.sh: shared guard. Reads
  tool_input.body/.title, allows CJK or pirate-flavoured text, blocks plain
  English via exit 2. Fails open on malformed payloads.
- Wired for Claude (.claude/settings.json PreToolUse), Codex
  (.codex/config.toml PreToolUse) and Cursor (beforeMCPExecution adapter).
- Documents the rule in AGENTS.md, the canonical pr-and-commit-rules.md and
  the Cursor rule so platforms without hook support apply it manually.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Use a slug for the release-note filename; document slug naming in AGENTS.md

Release-note filenames don't need to be the PR number — a short descriptive
slug works too (the PR link is resolved at release time). Rename the new note
accordingly and note this in AGENTS.md's directory reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [autofix.ci] apply automated fixes

* [AI] Auto-label PRs with Chinese descriptions as "ai spam" via CodeRabbit

Add a CodeRabbit labeling instruction (auto_apply_labels is already on) that
applies the "ai spam" label when a PR description contains Chinese/CJK
characters — a strong signal of AI-generated spam for this English-language
project.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Exempt CodeRabbit-addressed comments from the Chinese/pirate voice hook

CodeRabbit parses its commands (@coderabbitai review/resolve/etc.) as plain
English, so the github-comment-style guard now skips any comment mentioning
@coderabbitai / @coderabbit instead of forcing it into Chinese or pirate.
Documented the exception in the canonical and Cursor rule files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Key CodeRabbit voice exemption on authorship, not mentions

The hook only ever runs on the agent's own outgoing comments, so CodeRabbit's
own comments are already out of scope (it posts under its own identity). Drop
the @coderabbitai mention bypass — a comment merely name-dropping the bot is
still the agent's prose and must follow the Chinese/pirate rule, closing an
easy plain-English bypass. Docs updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Pin CodeRabbit reviews to English

CodeRabbit was reading AGENTS.md / pr-and-commit-rules.md (which ask
contributors to comment in Chinese/pirate) and applying that to its own
reviews, posting them in Chinese. Set `language: en-US` and `tone_instructions`
so the bot's own reviews, summaries and replies stay in English; the
Chinese/pirate rule is for contributor/agent comments, not CodeRabbit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Replace Chinese/pirate comment voice with a robot-emoji prefix

Scrap the 简体中文/pirate voice scheme (and its CodeRabbit language override and
Chinese-based "ai spam" label) in favour of one simple rule: every GitHub
comment, review or issue an agent posts must be prefixed with 🤖. The shared
guard now blocks any body — or, for issues, title — that doesn't start with the
robot emoji; docs and per-platform wiring updated to match. .coderabbit.yaml is
restored to its original state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Silence SC1007 false positive on CDPATH= cd in Cursor MCP adapter

shellcheck flags the intentional `CDPATH= cd` empty-env prefix as SC1007
(mistaking it for an assignment). Add a scoped inline disable directive on that
line; behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Fail closed on guard execution errors in Cursor MCP adapter

The adapter previously allowed the call on any non-0/2 exit from
github-comment-style.sh, so a broken or missing guard would silently disable
enforcement. Deny on unexpected exits instead (matching guard-shell.sh), with a
message that marks it as an execution problem rather than a real policy denial.
The shared guard still fails open on malformed payloads (its own exit-0 choice).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Add hook requiring a blank PR template when agents create PRs

New shared guard pr-template-blank.sh blocks mcp__github__create_pull_request
unless the body is the repo's PR template, unmodified (cosmetic whitespace
aside) — agents must leave it blank for the human, per AGENTS.md. Wired for
Claude (PreToolUse), Codex (PreToolUse) and Cursor (the beforeMCPExecution
adapter now dispatches per-tool to the right guard). Docs and a release note
updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lqu3eZi5djm2cPAEm3yVht

* [AI] Simplify agent-hook guard scripts

- github-comment-style.sh: fold the empty/whitespace-only case into the
  prefix check, dropping a redundant tr subshell per field.
- pr-template-blank.sh: drop the dead CR strip in canon() (the trailing
  whitespace sub already removes a trailing carriage return).
- before-mcp-github.sh: emit the constant allow payload with printf instead
  of spawning jq on the common (allow) path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] Drop duplicated PR-template/robot-emoji rules now that hooks enforce them

The PR-template-blank and GitHub-comment robot-emoji-prefix rules are enforced
by cross-platform hooks, so the copies scattered across AGENTS.md and the
Cursor rules file are redundant. Remove them and point at the canonical
pr-and-commit-rules.md, which keeps the full rule (including the PR-template
Chinese exception that no hook can enforce). Also delete the internal
PR-template-guard release note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] Drop "enforced by hooks" wording from the PR/comment rule docs

State the rules plainly without the meta-commentary about hook enforcement.
Keeps the actual rules (don't fill the PR template, prefix GitHub
comments/reviews/issues with 🤖, the Chinese exception, and the
your-own-comments-only note) intact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] Trim enforcement meta-commentary; shorten robot-emoji release note

Drop the "isn't enforced automatically" / "handled by tooling" framing from
AGENTS.md and pr-and-commit-rules.md (keeping the rule and the "apply it
yourself" responsibility), and shorten the robot-emoji-prefix release note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] Fail closed on unreadable payloads in the GitHub agent guards

Align the new guards with the git-guard.sh / guard-shell.sh convention: fail
closed when the hook payload can't be read, fail open only on a genuinely
absent optional field.

- github-comment-style.sh: block on invalid JSON / missing / non-object
  .tool_input; allow only an absent body/title within a valid object.
- before-mcp-github.sh: deny on a jq parse failure / missing .tool_name
  instead of falling through to allow.
- pr-template-blank.sh: an absent/null body now fails open (previously it
  normalized to "" and wrongly blocked PR creation); an empty-string body is
  still treated as a real non-template submission.
- .codex/config.toml: describe the full guard scope (comment body + issue
  title) in the hook comment and statusMessage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* speed up electron builds (#8337)

* size up runners, skip translations where possible

* note

* mdx -> md (#8338)

* mdx -> md

* [AI] Outlaw .mdx in the docs package

Docusaurus 3 compiles .md through MDX, so JSX and imports work in plain
.md files and there is no need for the .mdx extension. Narrow the
enforce-doc-links remark plugin to only accept .md: reject any .mdx
source file at build time, flag links that target a .mdx file, and drop
the .mdx branches from the directory scanner and link resolution.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* [AI] Add performance indexes for transactions table (#8335)

* [AI] Add performance indexes for transactions table

* release notes

* [AI] Remove unselective tombstone-only index from performance migration

* [AI] api: make the browser build work in consumer production bundles (#8289)

* api: make the browser build work in consumer production bundles

The browser build shipped `new Worker(new URL("./worker.js", import.meta.url))`
in dist/browser.js. A consumer bundler (Vite/Rollup) recognizes that as a worker
entry and re-bundles the already-prebuilt worker.js from scratch, which desyncs
the absurd-sql/connection RPC so `init` throws a structured-clone error. It only
worked in dev and in the package's own e2e because both serve dist verbatim.

Make the browser build fully self-contained instead:

- Inline the worker into browser.js and spawn it from a Blob URL, so consumer
  bundlers never see a worker entry to re-bundle. The worker is built as an IIFE
  (classic worker), mirroring the web app's kcab.worker.
- Embed the sql.js wasm and the default filesystem data (migrations + default
  DB) into the worker so it performs no PUBLIC_URL asset fetches:
  - loot-core sqlite gains an opt-in `setWasmBinary` (dormant for web/node);
  - the worker installs a scoped fetch shim serving the embedded data/* files
    from a sentinel base URL.
- Share the asset-collection logic between the Node disk copy and the embedded
  build via scripts/embedded-assets.mjs so the two never drift.

Result: `import '@actual-app/api'` + `init()` works in any bundler with zero
config; only COOP/COEP headers remain required (SharedArrayBuffer).

Adds an e2e (e2e/consumer + e2e/global-setup.mjs) that builds a real consumer
app for production and boots it under COOP/COEP — coverage the verbatim-dist
harness can't provide. Docs note the build is self-contained and that
cross-origin isolation is still required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: address review feedback (guard DOM lookup, revoke blob URL on worker failure)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: address review nitpicks (drop BodyInit cast, reword release note)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: build the browser worker via Vite ?worker&inline

Replace the hand-rolled worker inlining (a custom Vite plugin that read the
prebuilt worker.js off disk and inlined it as a string, plus a second build
config and a build-ordering dependency) with Vite's native `?worker&inline`
import. This collapses the two browser build configs into one, removes the
`virtual:actual-worker-code` module and the manual Blob URL spawn, and drops
the worker-before-facade build step.

Vite's `?worker&inline` sub-build doesn't receive vite-plugin-node-polyfills'
global-shim injection (the plugin writes it to `build.rollupOptions`, but the
worker sub-build reads `worker.rollupOptions`), so the worker crashed on
`process is not defined`. Patch the plugin to also emit the injection on
`worker.rollupOptions` — additive and backwards compatible (the web app build,
including loot-core's nodePolyfills worker, is unaffected).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: embed browser assets via Vite, drop the embedded-assets script

Replace scripts/embedded-assets.mjs with Vite-native asset imports in the
worker entry: `?inline` for the sql.js wasm and default DB, `import.meta.glob`
(`?raw`) for the migrations. The worker builds the default-filesystem wire
format from those at module load, so the embedded set comes straight from
loot-core and can't drift.

The Node build only needs migrations + the default DB on disk (it reads them at
runtime); the old script also wrote sql-wasm.wasm and the data/ fetch tree,
which are dead now that the browser worker is self-contained. Replace
writeEmbeddedAssetsToDist with a small closeBundle copy of just those two.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: simplify embedded data map; drop loot-core comment churn

Merge the worker's binData/textData into a single dataFiles map (Response
accepts both bytes and strings), collapsing the fetch shim's two lookups into
one. Revert the unrelated comment edits to loot-core's backend-worker.ts and
fs/index.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] api: rename e2e consumer-dist to consumer/dist; drop a prose comment

Use the standard `dist` directory name for the consumer fixture's build output
(now e2e/consumer/dist), and remove the verbose comment from index.browser.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] loot-core: own the default-filesystem assets; consumers stop reaching in

Add packages/loot-core/default-filesystem.mjs as the single source of truth for
loot-core's runtime assets (sql.js wasm, default DB, migrations) and the
data-file-index wire format, exported as @actual-app/core/default-filesystem.

- @actual-app/api: the browser worker embeds them via the actual-embedded-assets
  Vite plugin (which calls collectEmbeddedAssets), replacing the relative
  ?inline/?raw/import.meta.glob reaches into ../loot-core; the Node build copies
  migrations + default DB using the helper's paths. Drops the direct
  @jlongster/sql.js devDependency (loot-core resolves the wasm).
- @actual-app/web: stagePublicData copies from the helper's paths instead of
  hardcoding loot-core's tree and the sql.js wasm location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [AI] loot-core: scan migrations once when collecting embedded assets

collectEmbeddedAssets() read the migrations directory twice — once in its
own loop and once via buildDataFileIndex(). List the names once and pass
them through, keeping the index wire-format defined in a single place.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* Restore budget table scroll position when navigating back from spent transactions (#8144)

* feat: Restore budget table scroll position when navigating back from spent transactions page

* fix: Update transaction tests to include new categories and adjust assertions

* Add release notes for budget scroll position restoration

* refactor: Improve error handling when clicking on visible spent-amount cells, per suggestion from coderabbit bot

* refactor: revert changes to test budget, add separate scroll-test test budget

* revert previous snapshot changes

* Add gitignore pattern for personal devcontainer config

* fix: broken tests

* refactor: address coderabbitai feedback

https://github.com/actualbudget/actual/pull/8144#discussion_r3446850158

* fix: update VRT snapshots for onboarding screen

* [autofix.ci] apply automated fixes

* refactor: modify scrolling test to add categories to existing test budget instead of creating separate budget

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>

* [AI] Add design competition blog post for sidenav redesign (#8297)

* [AI] Add design competition blog post for sidenav redesign

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF

* [AI] Set design competition blog post publish date to 27th July 2026

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF

* [AI] Remove stray closing tags from design competition blog post

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HbXFM9ooWVw9SRA9No7vhF

* Update 2026-07-27-design-competition-sidenav.md

---------

Co-authored-by: Claude <noreply@anthropic.com>

* Always show stacked bar graph tooltip label on hover (#8356)

* Always show stacked bar graph tooltip label on hover

* Handle edge case with maxToolTipItems+1 labels showing

* Replace last item label instead of adding new one

* Filter visible items on non zero values for consistency

* make SimpleFIN token 'forbidden' check more flexible (#8339)

* make SimpleFIN token 'forbidden' check more flexible

* clear accessKey when token is updated

* https -> fetch

* [AI] Add tests for SimpleFIN token claim fix

Cover the flexible 'Forbidden' matching, full claim-response handling, and access-key invalidation when the setup token changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* note

* Update upcoming-release-notes/fix-simplefin-token-claim.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* coderabbit feedback

* [AI] Test SimpleFIN blank access key handling

Cover rejecting a blank claim response (not persisted) and re-claiming when an empty access key is cached.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
Co-authored-by: tabedzki <35670232+tabedzki@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: youngcw <calebyoung94@gmail.com>
Co-authored-by: Matt Farrell <10377148+MattFaz@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Dustin Brewer <mannkind@thenullpointer.net>
Co-authored-by: Matiss Janis Aboltins <matiss@mja.lv>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Alec Bakholdin <43560338+alecbakholdin@users.noreply.github.com>
Co-authored-by: clintharris <336401+clintharris@users.noreply.github.com>
Co-authored-by: Darwin Do <8429648+dsmaugy@users.noreply.github.com>
2026-07-03 19:58:35 +00:00
e8c7f8040e bcrypt -> argon2id (#7829)
* bcrypt -> argon2id

* coderabbit feedback

* copilot review

* switch hashing settings

* [AI] Add unit tests for sync-server password hashing

Cover password.js, focused on the bcrypt -> argon2id migration:
- loginWithPassword upgrades a legacy bcrypt hash to argon2id on a
  successful login, leaves it untouched on a failed login, and does not
  needlessly rehash an existing argon2id hash
- hashPassword/verifyPassword round-trip, bcrypt backward-compat, and
  graceful handling of non-string/malformed hashes
- bootstrapPassword/changePassword/checkPassword behaviour

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* dedupe minimatch

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 00:04:07 +00:00
lelemmGitHubcoderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
ae0594d294 ✨ Added support to pluggy date correction based on installments (#8380)
* Added support to pluggy date correction based on installments

* md

* Update packages/sync-server/src/app-pluggyai/app-pluggyai.js

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* date now considers instalments, originalDate is the date without it

* creating new instance instead of same obj

* code review

* aligning to code review

* simpler

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-07-02 19:07:08 +00:00
github-actions[bot]GitHubgithub-merge-queuegithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>Matt Fiddaman
8b5b182dbc 🔖 (26.7.0) (#8332)
* 🔖 (26.7.0)

* Generate release notes for v26.7.0

* update blog author

* Generate release notes for v26.7.0

* release notes

* Generate release notes for v26.7.0

* Generate release notes for v26.7.0

* Generate release notes for v26.7.0

* relink PRs from cherry-picked changes

* tweak wording of release summary

* update blog post date

* akahu experimental

---------

Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matt Fiddaman <github@m.fiddaman.uk>
2026-07-02 16:10:16 +00:00
Matt FiddamanandGitHub e891c2e30e reorganise the SimpleFIN key saving logic (#8362)
* remove the simplefin intercept in the secrets handler

* note
2026-06-29 21:04:27 +00:00