Commit Graph
6 Commits
Author SHA1 Message Date
Jakob WennbergandClaude Fable 5 dc5aea4a35 feat(mcp): speak spec revision 2026-07-28 (stateless core) (#1277)
* feat(mcp): speak spec revision 2026-07-28 (stateless core)

Adopt the 2026-07-28 MCP spec revision on the connector endpoint while
keeping every handshake-era client (2025-06-18 and earlier) byte-identical:

- Accept per-request _meta protocol negotiation
  (io.modelcontextprotocol/protocolVersion); unsupported versions return
  UnsupportedProtocolVersionError (-32022) with the supported list.
- Implement server/discover (spec MUST): supported revisions, capabilities
  including the extensions field, identity, instructions, freshness hints.
- Decorate results for stateless clients: required resultType, serverInfo
  in _meta, and CacheableResult ttlMs/cacheScope on tools/list,
  prompts/list, resources/list, resources/read.
- Validate the standard Mcp-Method/Mcp-Name request headers when present
  (HeaderMismatchError -32020); absence stays accepted.
- Declare the ratified MCP Apps extension (io.modelcontextprotocol/ui) in
  capabilities; the widgets already use the ratified mime type and
  _meta.ui.resourceUri shape, so no widget changes are needed.
- OAuth: include the RFC 9207 iss parameter on every authorization
  response (success and error) and advertise
  authorization_response_iss_parameter_supported in RFC 8414 metadata.

Resource-not-found already used -32602 and tools/list ordering was already
deterministic; both are covered by the new test file.

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

* fix(mcp): Mcp-Name covers params.uri, base64 sentinel, version-header consistency

Review follow-ups against the transport spec text: Mcp-Name mirrors
params.name OR params.uri (resources/read), values arrive base64-wrapped
in the =?base64?...?= sentinel and must be decoded before comparison, and
an MCP-Protocol-Version header that disagrees with the _meta protocol
version is a HeaderMismatch. Absence of any header stays accepted since
this server supports handshake-era clients (spec-sanctioned leniency).

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 18:02:05 +02:00
Jakob Wennberg 7dde8cac82 fix(security): resolve the CodeQL backlog, three fixes and three documented false positives (#1225)
Triage of all 9 CodeQL alerts surfaced on main by #1223. None were introduced by that PR.

Fixed: the compliance-review artifact now unpacks to runner.temp instead of over the trusted checkout (actions/artifact-poisoning, critical); MCP LIKE patterns escape backslash first, which was a real correctness bug returning wrong rows for any search containing a backslash (js/incomplete-sanitization, 2 sites); and the mcp-oauth consent form action is HTML-escaped (js/reflected-xss, not exploitable because WHATWG URL already percent-encodes " < >, but & is not in that encode set).

Dismissed as false positives with reasoning recorded at each site and in DECISIONS.md: sie-export escapeQuotes, where doubling backslashes would violate SIE 4B, corrupt files in conformant readers and skew #KSUMMA under BFL 7-year retention; hashApiKey, where SHA-256 is correct for a 256-bit CSPRNG token and changing it would invalidate every live gnubok_sk_ key; and the DuplicateBookingDialog href, which is a DB UUID behind a literal path prefix.

Regression tests cover both behavioural fixes, including the escape ordering.
2026-07-27 14:02:25 +02:00
MattssonandClaude Opus 4.8 abe9ac9d8c Fix/attributes config (#926)
* fix(git): pin LF on generated extension registry and vitest snapshots

setup:extensions and vitest write these files with LF; with
core.autocrlf=true git expects CRLF and flags them as phantom
modifications on every dev/build run.

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

* fix(security): enforce MFA on mcp-oauth consent and gate viewer storno route

mcp-oauth/authorize renders an HTML consent page and issues 303 redirects that withRouteContext cannot express, so it kept raw getUser() and thereby skipped the AAL2 gate: a password-only (AAL1) session could approve consent that mints a long-lived, MFA-bypassing API key. Add a route-local requireAal2() step-up on GET and POST; AAL1 sessions redirect to /mfa/verify, BankID users are exempt.

Separately, POST /api/reports/vat-declaration/rc-basis-gaps/fix calls correctEntry() (storno of a posted entry) but lacked requireWrite, so viewer-role members could trigger it. Add { requireWrite: true }.

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

* fix(api): route transactions endpoints through withRouteContext

Migrate the transactions routes off hand-rolled supabase.auth.getUser() onto the MFA-enforcing withRouteContext wrapper; add requireWrite on mutating handlers (book, uncategorize, attach-document, ignore, batch-match, create-from-document). Behavior and response shapes preserved; tests updated to the wrapper mock pattern.

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

* fix(api): route SIE import and bank reconciliation through withRouteContext

Migrate import/sie and reconciliation/bank routes onto the MFA-enforcing wrapper; requireWrite on mutations (import execute, create-accounts, mappings write verbs, link/unlink/run/mark-opening-balance). Reads (status, unmatched-entries) stay ungated. Response shapes preserved; tests added/updated to the wrapper mock pattern.

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

* fix(api): route salary endpoints through withRouteContext

Migrate salary employees and runs routes (plus ku, payroll-config, tax-tables) onto the MFA-enforcing wrapper; requireWrite on mutations. Personnummer masking/encryption untouched; file downloads (AGI XML, payslip PDF, payment files) keep their headers. Two payment-file GETs retain requireWrite because they stamp *_file_generated_at and previously gated viewers. Tests added/updated to the wrapper mock pattern.

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

* fix(api): route report endpoints through withRouteContext

Migrate the read-only report routes (trial balance, balansrapport, resultatrapport, income statement, ledgers, KPI, VAT declaration, salary journal, monthly breakdown, journal register, continuity check, full archive, etc.) onto the MFA-enforcing wrapper. All read-only, no requireWrite. JSON/XLSX/PDF/ZIP response bodies and headers preserved byte-for-byte; tests updated to the wrapper mock pattern.

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

* fix(api): route invoices, skatteverket, agent and extension endpoints through withRouteContext

Migrate invoices, supplier-invoices, skatteverket tax-payments, and dynamic extension routes onto the MFA-enforcing wrapper with requireWrite on mutations. The two NDJSON streaming agent routes (invoke, onboarding/stream) use requireAuth() directly (the wrapper can't wrap a streaming response) so MFA is still enforced. skatteverket payment-file GET keeps requireWrite (stamps a generated-at field). Response shapes and file headers preserved; tests added/updated.

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

* fix(api): route documents, events, team and account endpoints through withRouteContext

Migrate documents, events, kpi/preferences, vat/validate, support/contact onto the MFA-enforcing wrapper with requireWrite on mutations. account/password, team/accept and team/members use requireAuth() directly (user-level or pre-membership flows with no active company context) so MFA is still enforced. events keeps its dual API-key-or-session auth. Document retention guard untouched; tests added/updated.

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

* fix(api): route settings and pending-operations endpoints through withRouteContext

Migrate settings (api-keys, oauth-clients, booking-templates, counterparty-templates, logo, company settings) and pending-operations (commit, bulk-commit, reject, edit-before-approve) onto the MFA-enforcing wrapper with requireWrite on mutations. Credential-guarding routes keep their per-user ownership filters. Response shapes preserved; tests added/updated to the wrapper mock pattern.

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

* chore(guards): ratchet raw-route-auth baseline 119->1 after A1 migration

Lock in the withRouteContext migration so the count cannot regress. The single remaining entry, mcp-oauth/authorize, is a documented exception (HTML consent + redirects, MFA enforced via route-local step-up). Record the campaign and requireWrite decisions in DECISIONS.md.

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

* feat(vat): add eSKD momsdeklaration file export for "Deklarera via fil"

Generate the Skatteverket eSKDUpload v6.0 XML file so users can file VAT by
upload instead of typing every ruta into the form. Extract buildFiledAmounts()
as the shared whole-krona source of truth (öre truncated per SFL 22 kap 1 §) so
the XML file and the manual-filing PDF can never disagree. Adds the /eskd API
route, an XML option in the report export menu, and the upload button on the
manual-filing card. Strings in sv + en.

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

* feat(vat): add 'vat_settlement' source type and update related components

* fix(booking): adjust search input layout and enable autofocus

* fix(vat): support 12-digit org numbers and adjust emission order for eSKD file

* fix(migration): add 'vat_settlement' to journal_entries.source_type CHECK

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 09:54:46 +02:00
Jakob WennbergandClaude Sonnet 5 ec27228a8e style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
Em dashes (—) and en dashes (–) had spread across comments, docs, tests,
and a few UI strings, reading as AI-generated boilerplate rather than
house style. Replaced each with punctuation matching its context: colon
for explanatory clauses, comma for asides, plain hyphen for numeric/legal
ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for
paired-dash asides. messages/en.json and messages/sv.json were fixed by
hand together to keep sv/en in sync.

Left untouched where the dash is the functional subject rather than
decorative punctuation: date-range-parser.ts's separator regex,
charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE
encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the
agent system-prompt files that already instruct against em dashes, and
a golden iXBRL test fixture compared byte-for-byte.

Also fixes two bugs surfaced along the way: an off-by-one in
ApiKeysPanel's scope-label split (a leftover from an earlier partial
pass), and a charset-repair test that had lost the literal en-dash it
exists to verify.

Regenerated the agent atom seed migration (skills:generate) since 27
SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes,
with an explicit carve-out for the functional-dash cases above.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-04 15:58:06 +02:00
Mattsson e4d4d8e4dc feat: enhance OAuth scopes and UI for agent-driven approval process (#544)
* feat: enhance OAuth scopes and UI for agent-driven approval process

* refactor: update OAuth scopes to enforce explicit user consent for write and approval actions
2026-05-20 13:39:02 +02:00
Mattsson 566ed72984 Bug/mcp connection issue (#541)
* feat(api): implement caching and logging in health check endpoint

- Added in-memory caching for health check responses to reduce load on Postgres.
- Introduced logging for error handling in health check.
- Updated response structure to exclude error details from public responses.

feat(api): enhance OAuth consent UI and scope handling

- Improved consent UI to reflect exact requested scopes and added better user guidance.
- Updated scope handling logic to ensure least-privilege access.
- Enhanced styling for better user experience and accessibility.

chore(docker): improve security and resource management in Docker setup

- Updated Docker Compose configuration to enforce read-only file systems and resource limits.
- Added health checks and logging options for better observability.
- Introduced optional Caddy reverse proxy for TLS termination.

fix(migrations): resolve ambiguity in create_company_with_owner function

- Dropped orphaned 3-arg overload of create_company_with_owner function.
- Recreated canonical 4-arg version with cash account seeding logic.
- Ensured proper permissions for function execution in Postgres.

* feat: enhance security checks for team membership in company creation

* test: add CSP tests for OAuth authorization endpoint

* feat: enhance error handling and reporting in bank file import process
2026-05-20 10:08:32 +02:00