Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "bankstatementparser.github.io",
"image": "mcr.microsoft.com/devcontainers/rust:1-1-bookworm",
"features": {
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "24"
}
},
"postCreateCommand": "cargo install ssg --locked --version 0.0.69 && make verify"
}
5 changes: 4 additions & 1 deletion .github/allowed_signers
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
sebastian.rousseau@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDjGRQyeM79nAb4GHcpGzXMKq7HE3xyEOev4gVsnBN1e
# SHA256:f6FG+guRNtT3R36oQFS4oWCx1d10nm+BoaIL3Tkh1r4 (rousseau-mb-neo)
sebastian.rousseau@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDjGRQyeM79nAb4GHcpGzXMKq7HE3xyEOev4gVsnBN1e
# SHA256:kIOPAavp1TCEauTr1tTIN3cv+tSs6F9m/4lZjuM9tqk (rousseau-mbp-m1)
sebastian.rousseau@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII32YuD6LxBOeFb5kG4Fqbm62kn9OkcHNPJtktO8iYVF
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ jobs:
persist-credentials: false

- name: Set up Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "20"
node-version: "24"

- name: HTML validation (recommended + WCAG rules)
run: npx --yes html-validate@10 "docs/**/*.html"

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.12"

Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,18 @@ jobs:
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v3
uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v3
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
# public/ and docs/ are generated output, templates/ is unreferenced legacy.
# public/ and docs/ are generated output.
config: |
paths-ignore:
- public
- docs
- templates
- node_modules

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v3
uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v3
with:
category: "/language:${{ matrix.language }}"
4 changes: 2 additions & 2 deletions .github/workflows/quality-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Setup Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: "20"
node-version: "24"

- name: Install Audit Tooling
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ permissions:
contents: read

env:
SSG_VERSION: 0.0.67
SSG_VERSION: 0.0.69

jobs:
release:
Expand All @@ -42,7 +42,7 @@ jobs:
- if: steps.cache-ssg.outputs.cache-hit != 'true'
run: cargo install ssg --locked --version "$SSG_VERSION"

- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: "3.12"

Expand Down Expand Up @@ -101,7 +101,7 @@ jobs:

- name: Upload dry-run artefacts
if: github.ref_type != 'tag' || inputs.dry_run
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: bankstatementparser-site-release-candidate
path: dist/
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,20 @@ jobs:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- name: Upload artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: SARIF file
path: results.sarif
retention-days: 5

- name: Upload to code scanning
uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v3
uses: github/codeql-action/upload-sarif@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v3
with:
sarif_file: results.sarif
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

- Read `README.md`, `DEVELOPMENT.md`, and `/Users/seb/Code/REPO-STANDARD.md`
before modifying this repository.
- Use locally installed `ssg` 0.0.63 for every build.
- Use locally installed `ssg` 0.0.69 for every build.
- Never edit generated output in `public/` directly. Source of truth is
`_posts/` for content and `_layouts/` for Tera templates.
- Preserve WCAG 2.2 AAA accessibility, zero findings, and 100 Lighthouse
Expand Down
38 changes: 37 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,41 @@ All notable changes to this website are documented here. The format follows

## [Unreleased]

## [0.0.6] - 2026-10-30

### Added

- Generated `llms-full.txt` alongside `llms.txt` in `scripts/post-build.py` to
provide single-request full documentation context for AI coding agents.
- Added property-based and unit tests in `tests/test_frontmatter.py` covering
`SOURCE_DATE_EPOCH` resolution, URL classification, and script-safe entity
encoding.

### Changed

- `KEYS.asc` and `.github/allowed_signers` trust a second maintainer signing
key, `SHA256:kIOPAavp1TCEauTr1tTIN3cv+tSs6F9m/4lZjuM9tqk` (rousseau-mbp-m1),
so release tags can be signed on either maintainer machine.
- Upgraded CI workflows to Node.js 24 (npm 11) and `ssg` 0.0.69, and bumped
GitHub Actions and `hypothesis` (`6.170.8`) dependencies (#38, #39, #41, #42).
- Refactored `scripts/post-build.py` and `_layouts/main.js` into modular
functions adhering strictly to complexity ceilings, removing 40 unused legacy
template files.

### Fixed

- `KEYS.asc` is now in OpenSSH allowed-signers format, so
`git -c gpg.ssh.allowedSignersFile=KEYS.asc tag -v <tag>` verifies release
tags. It previously held a bare public-key line that Git rejected as
"invalid key". `KEYS.md` documents the command and lists each key's
fingerprint.
- `scripts/post-build.py` now honours `SOURCE_DATE_EPOCH` when emitting
`<lastmod>` in `sitemap.xml`, ensuring reproducible builds across arbitrary
dates.
- Fixed unquoted dictionary keys in `scripts/release_notes.py`
(`first_release_changes`) and hardened template Content Security Policy
headers by removing `'unsafe-inline'`.

## [0.0.5] - 2026-10-11

### Changed
Expand Down Expand Up @@ -120,7 +155,8 @@ All notable changes to this website are documented here. The format follows
- Self-hosted asset delivery and zero third-party telemetry (#1).
- Dual licensing under Apache-2.0 OR MIT (#2, #3).

[Unreleased]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.5...HEAD
[Unreleased]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.6...HEAD
[0.0.6]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.5...v0.0.6
[0.0.5]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.4...v0.0.5
[0.0.4]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.3...v0.0.4
[0.0.3]: https://github.com/sebastienrousseau/bankstatementparser.github.io/compare/v0.0.2...v0.0.3
Expand Down
4 changes: 2 additions & 2 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ cff-version: 1.2.0
message: "If you reference the Bank Statement Parser documentation, please cite it as below."
title: "bankstatementparser.com: Fast, secure financial statement parsing documentation"
type: software
version: 0.0.5
date-released: 2026-10-11
version: 0.0.6
date-released: 2026-10-30
authors:
- family-names: Rousseau
given-names: Sebastien
Expand Down
6 changes: 3 additions & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Prerequisites

- Rust and `ssg` 0.0.63: `cargo install ssg --locked --version 0.0.63`
- Python 3.10 or later
- Node.js 20 or later
- Rust and `ssg` 0.0.69: `cargo install ssg --locked --version 0.0.69`
- Python 3.12 or later
- Node.js 24 or later

## Build and test

Expand Down
17 changes: 17 additions & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2024-2026 Sebastien Rousseau
# SPDX-License-Identifier: Apache-2.0 OR MIT

PREFIX ?= /usr/local
DESTDIR ?=
DOCDIR ?= $(DESTDIR)$(PREFIX)/share/doc/bankstatementparser/html

include Makefile

.PHONY: install uninstall

install: build
@install -d "$(DOCDIR)"
@cp -R public/. "$(DOCDIR)/"

uninstall:
@rm -rf "$(DOCDIR)"
19 changes: 17 additions & 2 deletions KEYS.asc
Original file line number Diff line number Diff line change
@@ -1,2 +1,17 @@
# OpenSSH public key used for signed bankstatementparser.com releases.
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDjGRQyeM79nAb4GHcpGzXMKq7HE3xyEOev4gVsnBN1e sebastian.rousseau@gmail.com
# OpenSSH allowed-signers file for signed bankstatementparser.com releases.
#
# Release tags are signed with SSH keys (git's gpg.format=ssh), not OpenPGP,
# so this file is in OpenSSH allowed-signers format rather than an
# ASCII-armoured keyring. Verify a signed Git tag with Git 2.34 or later:
#
# git -c gpg.ssh.allowedSignersFile=KEYS.asc tag -v v0.0.5
#
# Every key line is "principal keytype base64-key", with the key's
# fingerprint and host in the comment above it. KEYS.md lists the same
# fingerprints for out-of-band checks.
#
# Maintainer: Sebastien Rousseau
# SHA256:f6FG+guRNtT3R36oQFS4oWCx1d10nm+BoaIL3Tkh1r4 (rousseau-mb-neo)
sebastian.rousseau@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDjGRQyeM79nAb4GHcpGzXMKq7HE3xyEOev4gVsnBN1e
# SHA256:kIOPAavp1TCEauTr1tTIN3cv+tSs6F9m/4lZjuM9tqk (rousseau-mbp-m1)
sebastian.rousseau@gmail.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII32YuD6LxBOeFb5kG4Fqbm62kn9OkcHNPJtktO8iYVF
15 changes: 13 additions & 2 deletions KEYS.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# Release signing keys

Every release tag is an annotated, cryptographically signed Git tag. Verify a tag with:
Every release tag is an annotated, cryptographically signed Git tag. Tags are
signed with SSH keys, and `KEYS.asc` lists the trusted keys in OpenSSH
allowed-signers format. Verify a tag with Git 2.34 or later:

```sh
git fetch --tags --force
git tag -v v0.0.1
git -c gpg.ssh.allowedSignersFile=KEYS.asc tag -v v0.0.5
```

A good result names the principal `sebastian.rousseau@gmail.com` and one of
the fingerprints below. The release workflow checks tags against
`.github/allowed_signers`, which lists the same keys.

| Fingerprint | Host |
| :--- | :--- |
| `SHA256:f6FG+guRNtT3R36oQFS4oWCx1d10nm+BoaIL3Tkh1r4` | rousseau-mb-neo |
| `SHA256:kIOPAavp1TCEauTr1tTIN3cv+tSs6F9m/4lZjuM9tqk` | rousseau-mbp-m1 |
51 changes: 51 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Migration Guide

This guide covers migrating existing financial parsing pipelines to **Bank Statement Parser** from cloud OCR APIs, single-format Python/Rust libraries, and earlier `0.0.x` releases.

---

## 1. Migrating from Cloud OCR & SaaS Aggregators (Ocrolus, AWS Textract, Plaid)

Cloud document APIs introduce per-page fees, network latency (`1–5 s` per document), and third-party data custody risks. Bank Statement Parser runs 100% in-process with zero outbound network calls.

| Capability | Cloud OCR / Aggregator API | Bank Statement Parser |
| :--- | :--- | :--- |
| **Execution Boundary** | External vendor cloud | Local process / air-gapped VPC |
| **Telemetry & Egress** | Vendor logs & request metadata | Zero telemetry (`0` network calls) |
| **Median Latency** | `1,200 ms - 4,500 ms` | `< 0.8 ms` (digital streams) |
| **Balance Verification** | Best-effort field extraction | Deterministic arithmetic proof (`opening + net == closing`) |

### Replacement Pattern (Python)

```python
# Before: External HTTP upload to cloud OCR endpoint
# response = requests.post("https://api.vendor.example/v1/parse", files={"file": open("statement.pdf", "rb")})

# After: Local deterministic extraction with arithmetic balance proof
from bankstatementparser import BankStatementParser

parser = BankStatementParser()
statement = parser.parse_file("statement.pdf")
assert statement.balance_verified is True
```

---

## 2. Migrating from Single-Format Python Libraries (`mt940`, `ofxparse`, `csv`)

Instead of maintaining separate dependencies and bespoke normalization glue for each banking standard, consolidate onto the unified `Statement` and `Transaction` schema:

| Legacy Library | Format Scope | Bank Statement Parser Equivalent |
| :--- | :--- | :--- |
| `mt940` / `swift-mt940` | SWIFT MT940 only | `BankStatementParser` (`MT940` + `MT942` + structured `:86:` tags) |
| `ofxparse` / `ofxtools` | OFX 1.x / 2.x | `BankStatementParser` (SGML `1.x` + XML `2.x` OFX/QFX) |
| `xml.etree` custom scripts | ISO 20022 XML | `CamtParser` (`camt.052`, `camt.053`, `camt.054`) & `Pain001Parser` |
| `pandas.read_csv` | Delimited CSV | Statistical dialect, date format, and decimal auto-detection |

---

## 3. Upgrading Documentation & Site Releases (`v0.0.5` to `v0.0.6`)

* **Canonical Theme (`Visage`)**: All layouts in `_layouts/` now inherit from `_layouts/base.html`, `_layouts/header.html`, and `_layouts/footer.html` using `{{#extends "base"}}` and `{{!content}}`.
* **Header Search Slot**: Top navigation embeds `<span data-ssg-search></span>` inside `#navMenu`, which `ssg 0.0.69` populates at build time with `#ssg-search-btn`.
* **Verification Gate**: Run `make verify` to execute SPDX header checks, frontmatter validation, WCAG 2.2 AAA contrast verification, property tests, and `ssg audit`.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ help:
@echo " make clean - Remove build artifacts and temporary files"

build:
@rm -rf public
@ssg build --content _posts --template _layouts --output public
@python3 scripts/post-build.py

test:
@python3 scripts/regression-test.py
@node --test tests/property.test.js

audit: contrast validate
ssg audit -f ssg.toml -o public --severity warn --fail-on warn

contrast:
@python3 scripts/audit-contrast.py
@python3 audit/contrast.py

validate:
@python3 scripts/validate-frontmatter.py
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.0.5
0.0.6
Loading
Loading