Repository navigation
Releases: michaelsanford/Mortimer
Release list
v1.1.1
Loonie · patch release
A security and CI maintenance release. No user-facing behaviour changes — all calculations, storage, and UI are identical to v1.1.0.
Security
Four transitive dependencies carrying high-severity advisories are now pinned to patched releases. All four reached the project through a single devDependency, @cyclonedx/cyclonedx-npm (the SBOM generator), and none of them were ever part of the shipped browser bundle — no deployed version of Mortimer was exposed.
| Package | Advisory | Pinned to |
|---|---|---|
brace-expansion |
DoS via unbounded expansion length / intermediate arrays (bypassing the CVE-2026-14257 mitigation) | 2.1.4 |
fast-uri |
GHSA-7p8r-x3mc-p8w7 | 3.1.5 |
ip-address |
GHSA-mwp4-54f8-5fhr — SSRF / trust-boundary bypass, plus two moderates | 10.4.0 |
js-yaml |
Quadratic CPU consumption in !!omap resolution (CVE-2026-59870 not backported) |
4.3.1 |
Each pin is the minimum patched release inside the existing major version, so no consumer in the dependency chain sees a breaking change.
One moderate advisory is also resolved: postcss moves to 8.5.26, clearing GHSA-fxqj-rqcc-2cmp — an incomplete fix of GHSA-6g55-p6wh-862q where an attacker-controlled sourceMappingURL could read arbitrary .map files when from is unset.
npm audit reports 0 high or critical findings, down from 3 high. A single moderate remains (tar, GHSA-r292-9mhp-454m), below the pipeline's high gate.
Fixed
-
Vulnerability scan results now reach GitHub code scanning. The SBOM & Vulnerability Scan job had never successfully uploaded its SARIF report. Grype derives each result's
physicalLocation.artifactLocationfrom the scan source's file paths, and a CycloneDX SBOM fromcyclonedx-npmrecords none, so every upload was rejected withlocationFromSarifResult: expected artifact location. The gate was correctly failing builds, but the findings were only ever visible in raw job logs. A new normalization step anchors location-less results topackage-lock.jsonbefore upload. -
Qodana no longer fails on Dependabot pull requests. Dependabot-triggered
pull_requestruns read from the Dependabot secret store, soQODANA_TOKENresolved empty and the scan exited 1 on its license check before analysing anything. The job is now skipped for that actor; pushes tomainand the weekly scheduled scan still cover the full tree.
What's Changed
- chore(problems): fix some Qodana findings by @michaelsanford in #30
- fix(ci): unbreak Grype SARIF upload and pin patched transitive deps by @michaelsanford in #34
- ci(qodana): skip scan on Dependabot pull requests by @michaelsanford in #33
- Add Ko-fi username to FUNDING.yml by @michaelsanford in #31
- build(deps-dev): bump postcss from 8.5.22 to 8.5.26 by @dependabot in #35
Toolchain also advanced since v1.1.0: TypeScript 7, @types/node 26, cyclonedx-npm 6, Vite 8.1.5, oxlint 1.75, Vitest 4.1.10. Runtime dependencies moved only within patch/minor — React 19.2.8, lucide-react 1.25.
Verifying this release
Artifacts are signed keylessly with cosign via GitHub OIDC, and carry build provenance attestations.
# Verify the signature bundle
cosign verify-blob mortimer-v1.1.1.zip \
--bundle mortimer-v1.1.1.zip.bundle \
--certificate-identity-regexp '^https://github\.com/michaelsanford/Mortimer/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# Verify build provenance
gh attestation verify mortimer-v1.1.1.zip --repo michaelsanford/MortimerA CycloneDX SBOM for this release is attached as mortimer-v1.1.1-sbom.json.
Full changelog: v1.1.0...v1.1.1
v1.1.0
What's Changed
- feat(ui): reposition print button to header by @michaelsanford in #28
- feat(rate-comparer): allow toggling offer visibility and add delete confirmation by @michaelsanford in #29
Full Changelog: v1.0.0...v1.1.0
v1.0.0
Mortimer v1.0.0 — "Loonie" 🪙
First Full Release 🎉 💰
The definitive first production release of Mortimer, a privacy-first Progressive Web App for simulating mortgage paydowns, comparing renewal and refinancing offers, and planning home equity borrowing — built specifically for Canadian mortgages.
Every calculation runs 100% in your browser. No backend, no analytics, no cookies — your financial data never leaves your device.
✨ Highlights
📊 Dashboard
An at-a-glance view of your mortgage profile: remaining balance, interest paid to date, overall progress paid off, and time saved from extra payments.
💸 Paydown Simulator
Model lump-sum payments, double-up schedules, and payment increases, then watch your amortization shorten in real time. Includes an outcome zone, household-income and estimated-net-income context, delta rows, and the ability to pull offers directly from the Rates Comparer.
🔁 Rates Comparer
Compare renewal and refinancing scenarios side-by-side, including IRD and three-month interest penalty models, break-even analysis, a comparison charts dashboard, and estimated remaining amortization at term end. Export scenarios as calendar reminders (ICS) or a printable report.
🏠 Reno & HELOC Planner
Estimate available home equity under Canadian regulatory caps (80% LTV total / 65% HELOC limit), reorder renovation projects, and plan financing with an editable checklist.
📈 Variable-Rate Stress Testing
Stress-test variable-rate scenarios, view break-even charts, and calculate your trigger rate.
🍁 Canadian Mortgage Math
Correct semi-annual compounding for fixed rates and monthly compounding for variable rates, across every payment frequency:
- Monthly, semi-monthly
- Bi-weekly (regular & accelerated)
- Weekly (regular & accelerated)
🔐 Privacy & Security
- Fully client-side — data stored only in browser
localStorage - Optional passcode lock with AES-GCM encryption and PBKDF2 key derivation (100,000 iterations)
- WebAuthn biometric unlock layered on top of your PIN
- Automatic session inactivity auto-lock
- Export / import profiles; one-click clear-all-data
- PIPEDA and Loi 25 (Quebec) compliant
🌐 Localization & UX
- Bilingual English / French interface with locale-aware number and currency formatting
- System theme matching (light / dark)
- Guided onboarding tour
- Full offline support via service worker, with an in-app update banner
- Debounced autosave with visual status indicators
- Installable as a PWA with a fixed mobile bottom-nav
🛠️ Tech Stack
React 19 + TypeScript 6 · Vite 8 · Chart.js · Lucide icons · Oxlint
✅ Quality & Supply Chain
- Vitest test suite with V8 coverage reporting in CI
- Qodana static analysis
- CycloneDX SBOM generation with Grype vulnerability scanning (high/critical CVEs fail the build)
- Content Security Policy and security headers
Full documentation: see the README · Versioning scheme: VERSIONING.md
Released under the MIT License.
What's Changed
- feat(pwa): full offline support and update banner by @michaelsanford in #7
- fix(deploy): split upload and deploy into separate jobs to prevent duplicate pages artifact by @michaelsanford in #8
- fix(sw): use unambiguous placeholder so swVersionPlugin replaces code not comment by @michaelsanford in #10
- feat(paydown): outcome zone, double-up slider, taller chart, household income by @michaelsanford in #11
- Add qodana CI checks by @qodana-cloud[bot] in #12
- fix(qodana): resolve reported static analysis warnings by @michaelsanford in #13
- chore(git): ignore Qodana SARIF reports and organize README badges by @michaelsanford in #14
- feat(comparer): improve renewal comparison table and add charts dashboard by @michaelsanford in #15
- test(comparer): add component integration tests and resolve linter warnings by @michaelsanford in #16
- fix(comparer): resolve qodana findings for redundant conditionals and duplicate test code by @michaelsanford in #17
- Add code coverage (Vitest V8) and remediate 0% components by @michaelsanford in #18
- CI health: fix flaky async tests + bump deprecated action versions by @michaelsanford in #19
- feat(paydown): connect simulator to rates comparer offers by @michaelsanford in #20
- feat(ux): implement system theme matching, onboarding tour, and HELOC project reordering by @michaelsanford in #21
- feat(modeling): implement variable rate stress testing, break-even chart, dual ICS exports, and print report action by @michaelsanford in #22
- feat(security): implement webauthn biometric unlock, settings, and session inactivity auto-lock by @michaelsanford in #23
- fix: lint error, qodana trigger, stress test slider placement by @michaelsanford in #24
- fix: resolve Qodana code quality findings by @michaelsanford in #25
- fix(simulator): paydown simulator fixes, renaming, delta and estimated net income rows by @michaelsanford in #26
- feat(locale): add locale-aware inputs and formatted numeric displays by @michaelsanford in #27
New Contributors
- @qodana-cloud[bot] made their first contribution in #12
Full Changelog: v0.1.0...v1.0.0
v0.6.0 - Half-Dollar
What's Changed
- feat(ux): implement system theme matching, onboarding tour, and HELOC project reordering by @michaelsanford in #21
- feat(modeling): implement variable rate stress testing, break-even chart, dual ICS exports, and print report action by @michaelsanford in #22
- feat(security): implement webauthn biometric unlock, settings, and session inactivity auto-lock by @michaelsanford in #23
- fix: lint error, qodana trigger, stress test slider placement by @michaelsanford in #24
- fix: resolve Qodana code quality findings by @michaelsanford in #25
Full Changelog: v0.5.0...v0.6.0
v0.5.0 - Shinplaster
What's Changed
- Add code coverage (Vitest V8) and remediate 0% components by @michaelsanford in #18
- CI health: fix flaky async tests + bump deprecated action versions by @michaelsanford in #19
- feat(paydown): connect simulator to rates comparer offers by @michaelsanford in #20
Full Changelog: v0.4.0...v0.5.0
v0.4.0 - Quarter
What's Changed
- Add qodana CI checks by @qodana-cloud[bot] in #12
- fix(qodana): resolve reported static analysis warnings by @michaelsanford in #13
- chore(git): ignore Qodana SARIF reports and organize README badges by @michaelsanford in #14
- feat(comparer): improve renewal comparison table and add charts dashboard by @michaelsanford in #15
- test(comparer): add component integration tests and resolve linter warnings by @michaelsanford in #16
- fix(comparer): resolve qodana findings for redundant conditionals and duplicate test code by @michaelsanford in #17
New Contributors
- @qodana-cloud[bot] made their first contribution in #12
Full Changelog: v0.3.0...v0.4.0
v0.3.0 - Dime
What's Changed
- feat(paydown): outcome zone, double-up slider, taller chart, household income by @michaelsanford in #11
Full Changelog: v0.2.0...v0.3.0
v0.2.0 - Nickel
What's Changed
- feat(pwa): full offline support and update banner by @michaelsanford in #7
- fix(deploy): split upload and deploy into separate jobs to prevent duplicate pages artifact by @michaelsanford in #8
- fix(sw): use unambiguous placeholder so swVersionPlugin replaces code not comment by @michaelsanford in #10
Full Changelog: v0.1.0...v0.2.0
v0.1.0 - "Penny"
Mortimer v0.1.0 — Penny 🪙
The humble first coin. Now phased out, but historically iconic — and so begins Mortimer.
We're excited to ship the very first public release of Mortimer, a privacy-first Progressive Web App for Canadian mortgage planning. Every calculation runs entirely in your browser — no data ever leaves your device.
✨ What's in this release
Core App
Mortimer launches with four fully-featured tools tailored to the nuances of the Canadian mortgage market:
- Dashboard — an at-a-glance summary of your mortgage profile: remaining balance, interest paid to date, and time saved through accelerated payments.
- Paydown Simulator — model lump-sum payments, double-up schedules, and payment increases to see exactly how much amortization time each strategy saves.
- Rates Comparer — compare renewal offers and refinancing scenarios side-by-side, including IRD and three-month interest penalties.
- Reno & HELOC Planner — estimate available home equity and plan renovation financing through a HELOC.
- Settings & Privacy — export and import profiles, enable optional passcode encryption via Web Crypto API key derivation, and clear all local data.
All mortgage math uses semi-annual compounding (Canada's statutory standard) and supports all common payment frequencies: monthly, semi-monthly, bi-weekly (regular and accelerated), and weekly (regular and accelerated).
Internationalization
Mortimer ships with support for 7 languages out of the box, including English and French (Canada's two official languages) plus the top non-official community languages in Canada:
| Language | Locale |
|---|---|
| English | en |
| French | fr |
| Arabic | ar |
| Punjabi | pa |
| Spanish | es |
| Chinese (Simplified) | zh |
| Chinese (Traditional, HK) | zh-HK |
The language picker UI has been redesigned for clarity and ease of use.
Privacy & Compliance
- 100% client-side — no backend, no analytics, no cookies
- Optional passcode lock with Web Crypto key derivation
- PIPEDA and Loi 25 (Quebec) compliant
- Data stored only in browser
localStorage
Supply Chain Security
Mortimer's CI pipeline generates a CycloneDX 1.6 SBOM on every run, published as a build artifact, and scans it automatically for known vulnerabilities using Grype. The deploy workflow is gated on a clean CI run, so no build with a failing vulnerability scan can reach production.
🔧 Infrastructure
- CI pipeline with SBOM generation and vulnerability gate
- GitHub Pages deployment, gated on CI success
- Automated release workflow with version-stamped footer
What's Changed
| PR | Change |
|---|---|
| #1 | Add CycloneDX SBOM generation and Grype vulnerability gate |
| #2 | Gate Deploy workflow on a successful CI run |
| #3 | Unbounded number inputs and aligned dropdown caret |
| #4 | Add top 5 Canadian non-official languages and redesigned language picker |
| #5 | Standard release and deploy workflow with footer version stamp |
| #6 | Add VERSIONING.md — currency-themed release codename convention |
Full Changelog: https://github.com/michaelsanford/Mortimer/commits/v0.1.0