Commit Graph

8 Commits

Author SHA1 Message Date
Jakob Wennberg 6c5c49f588 chore(compliance): upgrade to compliancemaxx@v2 (#419)
* chore(compliance): upgrade to compliancemaxx@v2

Per-PR check switches from `mode: pr` (deterministic scanners) to
`mode: review` (LLM-only diff review, ~90s, ~$0.05/PR). The nightly
audit workflow continues to provide the deeper scanner-backed coverage,
so concrete-pattern findings (secrets, CVEs, IaC misconfigs) are still
caught — just within 24 hours instead of immediately.

Trade-off accepted: PR feedback becomes shorter and more reasoned
(LLM judgement) rather than longer and more pattern-matched (scanner
output). Easier to act on per-PR; deep scanner coverage retained nightly.

  - compliance-pr.yml: @v1 mode:pr → @v2 (default mode: review)
  - compliance-swarm.yml: @v1 mode:swarm → @v2 mode:audit

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

* chore: re-trigger to pick up v2.0.1 action.yml fix

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:07:54 +02:00
Jakob Wennberg 97989285c2 chore(compliance): consume erp-mafia/compliancemaxx@v1 (#418)
* chore(compliance): consume erp-mafia/compliancemaxx@v1

Adds the consumer side of the new compliancemaxx orchestrator:

  - .github/workflows/compliance-pr.yml — single-job advisory check
    that calls `uses: erp-mafia/compliancemaxx@v1` on every PR.
    Threshold + skill selection live in .compliance/config.yml.
    `fail-on-findings: false` keeps it strictly advisory while findings
    bed in; flip to true after triage.

  - .compliance/config.yml — bootstrap config: all 5 skills enabled
    (oss-license, owasp-asvs-v5, iso-27001-2022, soc2, gdpr),
    severity_threshold_to_block=critical, no suppressions yet.

The orchestrator code, skill manifests, and reference docs live in the
new public repo: https://github.com/erp-mafia/compliancemaxx

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

* chore: retrigger compliance check

* chore(compliance): add full-swarm workflow (nightly + dispatch + label)

Adds the LLM-powered deep_audit alongside the existing PR-mode advisory
check. Triggers:
  - 02:00 UTC nightly cron
  - workflow_dispatch (manual)
  - PRs labeled `compliance:full-audit`

Authenticates to AWS Bedrock via the existing AWS_ACCESS_KEY_ID/SECRET
repo secrets (same path swedish-compliance-review.yml already uses).
`fail-on-findings: false` keeps it observational while findings bed in.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 22:11:33 +02:00
Jakob Wennberg ab63da8324 test: add real-Postgres smoke gate (pg-real) (#357)
* test: add real-Postgres smoke gate (pg-real)

Mocked Supabase tests cannot exercise triggers, RPCs, or RLS policies —
a migration that drops enforce_period_lock, mangles user_company_ids(),
or weakens an RLS policy ships green today. Closes that gap with a
small Vitest project `pg-real` running 5 smoke tests against a real
supabase/postgres:15 container in CI.

Covers: closed-period INSERT rejection, commit_journal_entry voucher
atomicity under concurrency, posted-entry immutability, RLS tenant
isolation on journal_entries, and audit_log UPDATE/DELETE rejection.

Also lands the bankid anonymization migration that was sitting
untracked from a prior task.

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

* test(pg-real): fix storage schema bootstrap + de-scope + PR review fixes

- Drop bankid anonymization migration from this PR. That change is
  separate scope (and has open compliance questions flagged by the
  Swedish review bot on #357); it will land in its own PR.
- Add tests/pg/bootstrap.sql to align storage.buckets/objects/foldername
  with what migrations expect before the replay loop. The supabase/postgres
  image ships only a partial storage schema; the rest comes from the
  storage-api service at runtime, which CI does not run. First pg-real run
  failed at migration 24 on "column public of relation buckets does not exist".
- Add concurrency group to the workflow so stacked PR commits cancel
  in-progress runs instead of queueing.
- Gate the pg-real vitest project on DATABASE_URL so a bare `vitest run`
  with no DB configured runs only the unit project. npm run test:pg is
  the opt-in entry point.

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

* test(pg-real): widen JWT claim setup so auth.uid() resolves under RLS

The rls.pg test came back with 0 rows instead of 1 — user_company_ids()
returned empty because auth.uid() didn't resolve to the seeded user.
Two fixes:
- Set both request.jwt.claims (whole object) and request.jwt.claim.sub
  (individual claim). Different Supabase auth.uid() versions read one or
  the other.
- Assert auth.uid() = expected userId immediately after the context
  switch, so the next failure points at the right layer instead of an
  unrelated empty-result assertion.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 11:24:45 +02:00
Jakob Wennberg 28df5d851e fix: cancel orphan draft when commitEntry fails + add compliance review CI (#302)
createJournalEntry now cancels the draft with a CAS guard (status='draft')
if commitEntry throws, so callers don't leave undeletable stuck drafts when
the commit RPC rejects (balance trigger, period lock, overload ambiguity).

Also adds a PR-triggered GitHub Actions workflow that runs Claude against
the diff using the swedish-* skills as authoritative references and posts
advisory compliance feedback as a PR comment.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:36:09 +02:00
Jakob Wennberg b387a77bfd chore: remove Sentry, consolidate migrations, add test coverage (#244)
* chore: remove Sentry, consolidate migrations, add test coverage

Remove @sentry/nextjs and all Sentry integration code — error tracking
now handled by Recapt. Consolidate 22 incremental migrations into a
single schema sync migration. Add 6 new test suites (auth, invoice
matching, VAT rules, opening balances) and extend report tests with
edge cases. Update Docker image name to gnubok, sync crontabs and
extension presets, fix CSP missing space, simplify journal entry
missing-document dialog.

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

* fix: remove viewer bank import migration never applied to production

20260413150000_viewer_bank_import_permissions.sql (PR #234) was merged
to main but never applied to the production database. It references
current_active_company_id() which does not exist in production either.
This breaks fresh installs and Supabase preview branches because the
migration runs before the consolidated schema sync.

Remove it so the migration chain matches production. The viewer bank
import RLS policies should be re-added in a future migration alongside
the helper functions they depend on.

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

* fix: correct delete policies for tables without company_id column

Seven tables in the generic delete-policy loop don't have a direct
company_id column, causing fresh installs to fail with "column
company_id does not exist". Fix by moving them out of the loop:

- invoice_items, journal_entry_lines, receipt_line_items,
  supplier_invoice_items → join through parent table
- extension_toggles, notification_settings, push_subscriptions →
  user-scoped (auth.uid() = user_id)

All policies match their existing production definitions.

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

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:52:00 +02:00
Jakob Wennberg f6a9889f0a fix: update Docker image name to match erp-mafia org
Repo moved from gnubok/gnubok to erp-mafia/erp-base. Updated GHCR image
reference in CI workflow and docker-compose.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:16:07 +01:00
Jakob Wennberg b5b004509d feat: add Docker support with self-hosted and hosted presets
Multi-stage Dockerfile (Node 22 Alpine), docker-compose for self-hosted
and hosted deployments, CI workflow for GHCR publishing, runtime env var
substitution, and cron sidecar with supercronic.

Aligns hosted extension preset with dev config (enable-banking,
ai-categorization, ai-chat, email).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:40:33 +01:00
Jakob Wennberg 03b569d708 refactor: consolidate extension system to general-only with manifest-driven architecture
- Remove all sector-specific extensions (construction, ecommerce, export,
  hotel, restaurant, tech) — only general-purpose extensions remain
- Move NE-bilaga and SRU export from extensions to core reports (lib/reports/)
- Move moms-box-mapping from extensions/export/shared to lib/vat/
- Replace per-extension API routes with catch-all dispatcher
  (app/api/extensions/ext/[...path]/route.ts)
- Add manifest.json for each extension with metadata, env vars, and deps
- Add api-routes.ts pattern for extension-defined API endpoints
- Add code generation scripts (generate-extension-registry, create-extension)
- Add extensions.config.json for opt-in extension loading
- Add extensions.schema.json for config validation
- Add email service interface with noop default (lib/email/service.ts)
- Add CI workflow (core-build.yml) to verify core builds with zero extensions
- Add migration 045: expand account_type CHECK for untaxed_reserves
- Update CLAUDE.md with comprehensive extension system documentation
- Update all report engines and bookkeeping services for new imports
- Clean up extensions.schema.json to only list existing extensions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:32:56 +01:00