feat(skatteverket): MCP wrappers for momsdeklaration + AGI filing (P0-5) (#692)
* feat(skatteverket): MCP wrappers for momsdeklaration + AGI filing (P0-5) Expose the complete Skatteverket extension as five MCP tools so VAT (momsdeklaration) and employer (AGI/arbetsgivardeklaration) filing can be driven from Claude. Commit = "send for BankID signing" (returns a signing link), never "file" — the user's signature in the browser is the irreversible act, kept outside the tooling. Tools (extensions/general/mcp-server/server.ts): - gnubok_vat_declaration_validate (compliance:read) — live POST /kontrollera - gnubok_vat_declaration_submit (skatteverket:write) — stages submit_vat_declaration - gnubok_vat_declaration_status (compliance:read) — GET /inlamnat + /beslutat - gnubok_agi_submit (skatteverket:write) — stages submit_agi - gnubok_agi_status (compliance:read) — local state + live kvittenser Architecture: - Core (lib/pending-operations/commit.ts) cannot import @/extensions (CI guard), so the two submit ops dispatch into the extension via the new Extension.services channel (first use): registry-resolved commitSubmitVatDeclaration / commitSubmitAgi run the SKV chain and return a shared SkvSubmitResult (lib/pending-operations/skatteverket-commit.ts). - Recoverable failures (extension disabled, no connection, rate-limited, still processing) release the op back to 'pending' via SkatteverketRecoverableError — same contract as AccountsNotInChartError — so the user reconnects and re-approves the SAME op. SKV business rejections reject the op. - No-drift: parseDeclarationRequest / loadAGIXml extracted to lib/declaration-prep.ts (buildMomsuppgift / buildAgiUnderlag / resolveRedovisare) so route, preview, and commit file identical figures. writeSkatteverketAudit hoisted to lib/audit.ts; read tools + executors write BFL audit rows too. - New scope skatteverket:write (opt-in, in STAGING_SCOPES so SoD ack fires), 4 structured error codes, sv/en strings, ApiKeysPanel row. - Migration 20260620120000 adds submit_vat_declaration / submit_agi to the pending_operations.operation_type CHECK (must apply to prod post-merge). Tests: 42 new across executors, MCP tools, declaration-prep, error-map, and the VAT commit chain. Full suite green (5287), build clean, lint-ratchet at baseline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci: add PR-Agent AI review (SHA-pinned, dedicated Bedrock key) Greptile went silent after #682 (app/account-side, not repo config). Add the open-source PR-Agent GitHub Action as a replacement, hardened for supply chain: - Pinned to the v0.36.0 commit SHA (ffe1f89), not the movable tag — the repo was recently transferred to a new, unverified org (The-PR-Agent), though it's the genuine original pr-agent (repo id 662766482, 11.5k stars). - Runs on a DEDICATED, minimal IAM key (bedrock:InvokeModel only) via PR_AGENT_AWS_* secrets — never the app's general AWS credentials. - Only /review runs automatically; /describe and /improve are disabled so PR descriptions are never overwritten. Requires three new secrets before it functions: PR_AGENT_AWS_ACCESS_KEY_ID, PR_AGENT_AWS_SECRET_ACCESS_KEY, PR_AGENT_AWS_REGION (EU region). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(pr-agent): handle push events + restrict push to /review PR-Agent skips synchronize (push) events by default, so the bot ran green but posted nothing. Enable handle_push_trigger and scope push_commands to /review. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(pr-agent): fix pr_actions (event list, not commands) + add synchronize pr_actions is the list of PR event actions to handle, not slash-commands. Setting it to ["/review"] removed every real event from the allowlist, so the bot skipped everything. Restore the default events + synchronize; command selection stays on the auto_review/describe/improve booleans (review-only). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(pr-agent): raise max_model_tokens to 64k for fuller diff coverage Default ~32k input window truncated large PRs. Sonnet 4.6 has 200k context. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * ci(pr-agent): use Claude Opus 4.8 (Sonnet 4.6 fallback) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(skatteverket): scope AGI status flips by salary_run_id Bot review (swedish-compliance) caught that commitSubmitAgi flipped agi_declarations status by (company_id, period) only. A correction run sharing the period would have its still-valid declaration co-flipped to rejected/ pending_signature. Scope both updates by salary_run_id (in scope from params) — more precise than the period-only route handler, which has no run id. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(pg): fix gen_random_bytes assertion for modern pgcrypto OpenSSL-backed pgcrypto (CI Postgres image) rejects gen_random_bytes(0) with 'Length not in range' rather than returning empty bytea, so the pre-existing 'returns empty bytea' assertion fails on every pg-real run (repo-wide, not specific to this PR). Assert the real contract — exactly n bytes for a positive n — instead of the version-dependent 0-byte edge case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
122bcbbcc1
commit
679b154ad2
@@ -0,0 +1,79 @@
|
||||
name: PR Agent
|
||||
|
||||
# AI pull-request review (PR-Agent, the original open-source reviewer — repo id
|
||||
# 662766482, same repo the qodo-ai/Codium-ai names redirect to). Replaces the
|
||||
# Greptile bot that went silent after #682.
|
||||
#
|
||||
# Supply-chain hardening:
|
||||
# * Pinned to an immutable commit SHA (v0.36.0), NOT a movable tag, because the
|
||||
# repo now sits under a recently-created, unverified org (The-PR-Agent).
|
||||
# * Runs on a DEDICATED, minimal IAM key (bedrock:InvokeModel only) supplied via
|
||||
# PR_AGENT_AWS_* secrets — never the app's general AWS credentials. A leaked
|
||||
# PR-Agent key can do nothing but invoke the one Bedrock model.
|
||||
#
|
||||
# Scope: ONLY /review runs automatically. /describe and /improve are disabled so
|
||||
# the bot never overwrites hand-written PR descriptions. Users can still invoke
|
||||
# any command interactively by commenting e.g. "/describe" or "/improve" on a PR.
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, ready_for_review, synchronize]
|
||||
issue_comment:
|
||||
types: [created, edited]
|
||||
|
||||
# One run per PR; cancel a superseded run when a new push lands.
|
||||
concurrency:
|
||||
group: pr-agent-${{ github.event.pull_request.number || github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
pr_agent:
|
||||
# Skip bot-authored events (vercel/supabase/etc.) to avoid feedback loops.
|
||||
if: ${{ github.event.sender.type != 'Bot' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: The PR Agent
|
||||
steps:
|
||||
- name: The PR Agent
|
||||
# Pinned to the v0.36.0 commit SHA (immutable) — do not switch to @v0.36.0.
|
||||
uses: The-PR-Agent/pr-agent@ffe1f89a4dafc7d8e88b9cf010a3233e30b49f43 # v0.36.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# ── DEDICATED Bedrock IAM key (bedrock:InvokeModel only) — NOT the
|
||||
# app's AWS_* secrets. litellm reads AWS_REGION_NAME; AWS_REGION is
|
||||
# set too for safety. Create these three repo/org secrets:
|
||||
# PR_AGENT_AWS_ACCESS_KEY_ID, PR_AGENT_AWS_SECRET_ACCESS_KEY,
|
||||
# PR_AGENT_AWS_REGION (an EU region, e.g. eu-west-1).
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.PR_AGENT_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.PR_AGENT_AWS_SECRET_ACCESS_KEY }}
|
||||
AWS_REGION_NAME: ${{ secrets.PR_AGENT_AWS_REGION }}
|
||||
AWS_REGION: ${{ secrets.PR_AGENT_AWS_REGION }}
|
||||
|
||||
# ── Model: Claude Opus 4.8 via the EU Bedrock inference profile, with
|
||||
# Sonnet 4.6 as fallback if the Opus profile isn't enabled for these
|
||||
# creds. custom_model_max_tokens is required because these ids are not
|
||||
# in PR-Agent's built-in token map.
|
||||
CONFIG.MODEL: "bedrock/eu.anthropic.claude-opus-4-8"
|
||||
CONFIG.MODEL_WEAK: "bedrock/eu.anthropic.claude-sonnet-4-6"
|
||||
CONFIG.FALLBACK_MODELS: '["bedrock/eu.anthropic.claude-sonnet-4-6"]'
|
||||
CONFIG.CUSTOM_MODEL_MAX_TOKENS: "200000"
|
||||
# Input window PR-Agent prunes the diff to fit. Default (~32k) truncated
|
||||
# large PRs; raise it so the whole diff is reviewed (Sonnet 4.6 = 200k ctx).
|
||||
CONFIG.MAX_MODEL_TOKENS: "64000"
|
||||
LITELLM.DROP_PARAMS: "true"
|
||||
|
||||
# ── pr_actions = which GitHub PR *event actions* trigger the bot
|
||||
# (NOT a command list). Default omits 'synchronize', so pushes are
|
||||
# skipped; we add it so every push is reviewed too.
|
||||
GITHUB_ACTION_CONFIG.PR_ACTIONS: '["opened", "reopened", "ready_for_review", "review_requested", "synchronize"]'
|
||||
# ── Which commands actually run on a handled event. Only review —
|
||||
# describe/improve off so the bot never rewrites the PR body or
|
||||
# pushes code suggestions.
|
||||
GITHUB_ACTION_CONFIG.AUTO_REVIEW: "true"
|
||||
GITHUB_ACTION_CONFIG.AUTO_DESCRIBE: "false"
|
||||
GITHUB_ACTION_CONFIG.AUTO_IMPROVE: "false"
|
||||
Reference in New Issue
Block a user