ksef_client 0.1.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +59 -0
- data/CONTRIBUTING.md +103 -0
- data/LICENSE +27 -0
- data/README.md +150 -0
- data/SECURITY.md +69 -0
- data/docs/REFERENCE.md +403 -0
- data/docs/errors.md +128 -0
- data/lib/ksef/configuration.rb +122 -0
- data/lib/ksef/environments.rb +85 -0
- data/lib/ksef/errors.rb +92 -0
- data/lib/ksef/fa3/schema/LICENSE.upstream.txt +21 -0
- data/lib/ksef/fa3/schema/bazowe/ElementarneTypyDanych_v10-0E.xsd +1 -0
- data/lib/ksef/fa3/schema/bazowe/KodyKrajow_v10-0E.xsd +1283 -0
- data/lib/ksef/fa3/schema/bazowe/StrukturyDanych_v10-0E.xsd +1 -0
- data/lib/ksef/fa3/schema/schemat_FA(3)_v1-0E.xsd +3950 -0
- data/lib/ksef/http/connection.rb +62 -0
- data/lib/ksef/http/error_handler.rb +83 -0
- data/lib/ksef/http/system_warning.rb +29 -0
- data/lib/ksef/problem_details.rb +143 -0
- data/lib/ksef/retry_policy.rb +77 -0
- data/lib/ksef/version.rb +5 -0
- data/lib/ksef.rb +32 -0
- data/lib/ksef_client.rb +5 -0
- metadata +130 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0e0a3a152f2257ff0f45b86a8027f6a48a8b1ff6612b940284c155bf1a9d6702
|
|
4
|
+
data.tar.gz: ffed0fa233572a528a77ffdcc0e0171a96f7a755ffff1dfc4561c955b15bc32b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c3c6068d0d7bbdc5ee4aad882950e13b497da3633b1e832357ae42597952c197734229dab9cd5b7f20680dbb4f3028291e953028fcae3a7ac9fe10a0a9465c7c
|
|
7
|
+
data.tar.gz: e99942deca0206d28f0919d58ad94bf83c6e9e689868b76e7968518d343ca0ea10fdb47a537a817ba537b7b83137c1ff9b6ba1ba9da89eaab0d8ac22823b9fb9
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here, following
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project adheres to
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
Every release entry states the **KSeF API version** and **FA schema revision** it
|
|
8
|
+
targets. The Ministry ships changes continuously, so users must be able to answer "which
|
|
9
|
+
gem version for which API state".
|
|
10
|
+
|
|
11
|
+
## [Unreleased]
|
|
12
|
+
|
|
13
|
+
## [0.1.0.rc1] — 2026-08-22
|
|
14
|
+
|
|
15
|
+
**Targets:** KSeF API 2.0 · FA(3) `1-0E` (`kodSystemowy` `FA (3)`, variant 3)
|
|
16
|
+
· upstream `CIRFMF/ksef-api@1c34fe27` (2026-07-21)
|
|
17
|
+
|
|
18
|
+
> **Prerelease. Not usable for invoicing.** This release exists to verify the trusted
|
|
19
|
+
> publishing pipeline and to claim the gem name. It contains the transport foundations
|
|
20
|
+
> only — authentication, encryption, sessions and the FA(3) builder are not implemented,
|
|
21
|
+
> so no invoice can be sent yet. Prereleases are not installed by `gem install
|
|
22
|
+
> ksef_client`; you would have to ask for this version explicitly.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Pinned upstream artifacts with SHA-256 manifest: the OpenAPI 3.0.4 contract
|
|
27
|
+
(78 paths, 302 schemas) and the FA(3) XSD with its three base schemas. Verified on
|
|
28
|
+
every test run and by `rake verify:artifacts`.
|
|
29
|
+
- `docs/REFERENCE.md`, the verification ledger — every externally sourced fact with its
|
|
30
|
+
source URL and retrieval date.
|
|
31
|
+
- `Ksef::Environments` with TEST, DEMO and PROD base URLs verified against each
|
|
32
|
+
environment's own OpenAPI document, plus a `custom(base_url:)` escape hatch that
|
|
33
|
+
requires HTTPS.
|
|
34
|
+
- `Ksef::Configuration` — frozen at construction for thread safety, with a redacting
|
|
35
|
+
`#inspect`, duck-typed logger validation, and rejection of unknown options.
|
|
36
|
+
- `Ksef::RetryPolicy` — idempotent-only retries with capped exponential backoff, honouring
|
|
37
|
+
`Retry-After` unclamped. Invoice submission is never auto-retried.
|
|
38
|
+
- Full error hierarchy under `Ksef::Error`, including `AuthorizationError` (403, with
|
|
39
|
+
`reason_code` and the structured `security` payload) and `ResourceGoneError` (410).
|
|
40
|
+
- `Ksef::ProblemDetails` — normalises both KSeF error envelopes (`application/problem+json`
|
|
41
|
+
and the deprecated `application/json` shapes) and degrades gracefully on non-JSON bodies.
|
|
42
|
+
- `Ksef::HTTP::Connection` — Faraday connection factory with TLS 1.2 floor, verification
|
|
43
|
+
always on, and error mapping.
|
|
44
|
+
- `Ksef::HTTP::SystemWarning` — surfaces the `X-System-Warning` advisory header the API
|
|
45
|
+
sets on successful responses.
|
|
46
|
+
- CI: test matrix across Ruby 3.2/3.3/3.4/4.0/head, nightly TEST integration, and a
|
|
47
|
+
tag-triggered release workflow using RubyGems Trusted Publishing.
|
|
48
|
+
|
|
49
|
+
### Notes
|
|
50
|
+
|
|
51
|
+
- The `ksef-docs` repository named in the design document does not exist; all upstream
|
|
52
|
+
documentation, the OpenAPI spec and the FA schemas live in `CIRFMF/ksef-api`.
|
|
53
|
+
- Endpoint paths carry no `/api` prefix — the base URL includes `/v2` and paths are
|
|
54
|
+
appended bare.
|
|
55
|
+
- The FA(3) schemas are MIT-licensed by Ministerstwo Finansów, so they are bundled with
|
|
56
|
+
the gem rather than fetched at first run.
|
|
57
|
+
- **The Ruby 3.2 floor is retained despite 3.2 reaching EOL upstream**, as a deliberate
|
|
58
|
+
exception to the EOL-drop policy (DESIGN.md §3). The full suite is verified green on
|
|
59
|
+
3.2.11. The EOL-drop rule governs 3.3 and later series.
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Getting set up
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bin/setup # bundle install + verify pinned artifacts
|
|
7
|
+
bundle exec rake # verify:artifacts, specs, RuboCop
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Development targets the current Ruby 4.0 patch (see `.ruby-version`) because the
|
|
11
|
+
strictest interpreter surfaces un-bundled-stdlib and deprecation issues locally. The
|
|
12
|
+
library itself supports MRI >= 3.2.
|
|
13
|
+
|
|
14
|
+
## The one rule that matters most
|
|
15
|
+
|
|
16
|
+
**Never invent an endpoint path, XML element name, namespace URI, or cryptographic
|
|
17
|
+
parameter.**
|
|
18
|
+
|
|
19
|
+
This gem talks to a tax authority. A plausible-looking guess that happens to be wrong
|
|
20
|
+
produces rejected invoices, or worse, silently malformed ones. So:
|
|
21
|
+
|
|
22
|
+
1. Every externally sourced fact goes in [`docs/REFERENCE.md`](docs/REFERENCE.md) with its
|
|
23
|
+
value, source URL and retrieval date, *before* the code depending on it is written.
|
|
24
|
+
2. The authoritative sources, in order: the integrator documentation portal, the
|
|
25
|
+
`CIRFMF/ksef-api` repository, the pinned OpenAPI spec, the pinned FA(3) XSD.
|
|
26
|
+
3. If a detail is not in the ledger and not verifiable from those sources, **stop and ask**
|
|
27
|
+
rather than guessing.
|
|
28
|
+
4. When the pinned artifacts and the design document disagree, the artifacts win. Update
|
|
29
|
+
the ledger and note the divergence in your PR description.
|
|
30
|
+
|
|
31
|
+
## Pinned artifacts
|
|
32
|
+
|
|
33
|
+
`spec/fixtures/openapi/open-api.json` and `lib/ksef/fa3/schema/**` are verbatim upstream
|
|
34
|
+
copies, checksummed in `docs/artifacts.sha256`. Do not edit them, not even whitespace.
|
|
35
|
+
|
|
36
|
+
If `rake verify:artifacts` fails, upstream changed. That is a finding to investigate and
|
|
37
|
+
ledger, not a checkout to repair. Refresh the files, update the manifest and the ledger,
|
|
38
|
+
and describe the behavioural impact in your PR.
|
|
39
|
+
|
|
40
|
+
## Constraints that are decided, not open
|
|
41
|
+
|
|
42
|
+
Please raise these for discussion rather than changing them in a PR:
|
|
43
|
+
|
|
44
|
+
- **Runtime dependencies are exactly four**: `faraday`, `nokogiri`, `bigdecimal`,
|
|
45
|
+
`zeitwerk`. A fifth needs a discussion first.
|
|
46
|
+
- **No upper bound on `required_ruby_version`**, ever.
|
|
47
|
+
- **The Ruby 3.2 floor stays**, despite 3.2 being EOL upstream — see DESIGN.md §3. Please
|
|
48
|
+
don't open a PR raising it, and don't reach for a 3.3+ API on the grounds that 3.2 is
|
|
49
|
+
past EOL.
|
|
50
|
+
- **`BigDecimal` for every monetary amount.** `Float` is forbidden in any monetary path.
|
|
51
|
+
- **Invoice submission is never auto-retried.**
|
|
52
|
+
- **No `VERIFY_NONE`**, no way to disable TLS verification.
|
|
53
|
+
- `lib/ksef/fa3/generated/` is codegen output — regenerate with `rake fa3:generate`, never
|
|
54
|
+
hand-edit.
|
|
55
|
+
|
|
56
|
+
## Style
|
|
57
|
+
|
|
58
|
+
- `# frozen_string_literal: true` in every file.
|
|
59
|
+
- `Data.define` for immutable value and response objects.
|
|
60
|
+
- UTF-8 throughout; XML serialised with an explicit `encoding="UTF-8"` declaration. Note
|
|
61
|
+
that file reads need an explicit encoding, since a non-UTF-8 locale otherwise yields
|
|
62
|
+
US-ASCII strings and breaks on Polish characters.
|
|
63
|
+
- No `RUBY_VERSION` string surgery.
|
|
64
|
+
- RuboCop enforces what it can; `bundle exec rubocop -a` for the mechanical parts.
|
|
65
|
+
|
|
66
|
+
## Tests
|
|
67
|
+
|
|
68
|
+
| Tier | Runs |
|
|
69
|
+
|---|---|
|
|
70
|
+
| Unit + recorded (WebMock/VCR) | every push, full Ruby matrix |
|
|
71
|
+
| Golden files, round-trip, crypto vectors | every push |
|
|
72
|
+
| Live TEST integration | nightly and pre-release only, never per-PR |
|
|
73
|
+
|
|
74
|
+
Coverage gate is 90% lines, excluding `generated/`. Live integration specs are tagged
|
|
75
|
+
`:integration` and read credentials only from `KSEF_TEST_NIP` / `KSEF_TEST_TOKEN` with
|
|
76
|
+
`KSEF_ENV=test`.
|
|
77
|
+
|
|
78
|
+
Never point tests at production. The suite aborts on `KSEF_ENV=prod`.
|
|
79
|
+
|
|
80
|
+
Cassettes must be scrubbed of tokens, JWTs and keys before committing.
|
|
81
|
+
|
|
82
|
+
## Releasing
|
|
83
|
+
|
|
84
|
+
1. Confirm no metadata placeholders were reintroduced: `grep -r UNRESOLVED-DESIGN-12-1`.
|
|
85
|
+
The release gate checks this too, but it is cheaper to notice here.
|
|
86
|
+
2. Update `CHANGELOG.md`, including the KSeF API version and FA schema revision targeted.
|
|
87
|
+
3. Confirm a **green nightly on the release commit**.
|
|
88
|
+
4. Do one deliberate local full-suite run on **Ruby 3.2** — the floor contract deserves a
|
|
89
|
+
look, not just a matrix tick. RuboCop cannot substitute for this: `TargetRubyVersion`
|
|
90
|
+
catches incompatible *syntax* but not post-3.2 *APIs*, so a method added in 3.3 or 3.4
|
|
91
|
+
passes lint and then `NoMethodError`s on a user's interpreter.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
mv Gemfile.lock /tmp/Gemfile.lock.dev
|
|
95
|
+
BUNDLE_PATH=/tmp/ksef-bundle-32 RBENV_VERSION=3.2.11 bundle install
|
|
96
|
+
BUNDLE_PATH=/tmp/ksef-bundle-32 RBENV_VERSION=3.2.11 bundle exec rake
|
|
97
|
+
mv /tmp/Gemfile.lock.dev Gemfile.lock
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The separate `BUNDLE_PATH` leaves your development gem set alone, and resolving without
|
|
101
|
+
the lockfile mirrors CI. Bundler on 3.2 cannot read a lockfile written by Bundler 4.
|
|
102
|
+
5. Tag `vX.Y.Z`. The release workflow runs the suite with `KSEF_RELEASE_CHECK=1`, checks
|
|
103
|
+
the tag against `Ksef::VERSION`, and publishes via Trusted Publishing.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tibor Molnár
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The FA(3) XML schemas bundled under `lib/ksef/fa3/schema/` are published by
|
|
26
|
+
Ministerstwo Finansów under the MIT licence; see
|
|
27
|
+
`lib/ksef/fa3/schema/LICENSE.upstream.txt` and docs/REFERENCE.md §1.
|
data/README.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# ksef_client
|
|
2
|
+
|
|
3
|
+
Ruby client for **KSeF 2.0**, Poland's national e-invoicing system (Krajowy System
|
|
4
|
+
e-Faktur), with a standalone **FA(3)** invoice builder.
|
|
5
|
+
|
|
6
|
+
Invoicing through KSeF has been a legal obligation since 2026-02-01 for taxpayers with
|
|
7
|
+
2024 gross sales above 200M PLN, and since 2026-04-01 for essentially everyone else. The
|
|
8
|
+
Ministry of Finance publishes official SDKs in C# and Java; this gem fills the Ruby gap.
|
|
9
|
+
|
|
10
|
+
> **Status: pre-release, under active development.** The transport foundations
|
|
11
|
+
> (configuration, environments, error model, HTTP layer) are in place. Authentication,
|
|
12
|
+
> encryption, sessions and the FA(3) builder are not implemented yet — see
|
|
13
|
+
> [Roadmap](#roadmap). The quickstart below is the **target** API for 0.1.0 and does not
|
|
14
|
+
> run today.
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
gem "ksef_client"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The gem is named `ksef_client`; the namespace is `Ksef`.
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
require "ksef_client" # defines Ksef, Ksef::Client, Ksef::FA3, ...
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quickstart (target API for 0.1.0 — not yet functional)
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
client = Ksef::Client.new(
|
|
32
|
+
env: :test,
|
|
33
|
+
auth: Ksef::Auth::Token.new(context_nip: "9999999999", token: ENV["KSEF_TOKEN"])
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
invoice = Ksef::FA3.build do |f|
|
|
37
|
+
f.seller nip: "9999999999", name: "ACME sp. z o.o.",
|
|
38
|
+
address: { street: "Prosta 1", city: "Warszawa", postal_code: "00-001", country: "PL" }
|
|
39
|
+
f.buyer nip: "1111111111", name: "Klient S.A.",
|
|
40
|
+
address: { street: "Długa 2", city: "Kraków", postal_code: "30-001", country: "PL" }
|
|
41
|
+
f.number "FV/2026/08/001"
|
|
42
|
+
f.issue_date Date.today
|
|
43
|
+
f.line name: "Consulting", qty: 10, unit: "godz.", net_unit_price: 150, vat: "23"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
result = client.send_invoice(invoice) # validate! → encrypt → session → submit
|
|
47
|
+
status = client.wait_until_accepted(result.reference)
|
|
48
|
+
status.ksef_number # => "9999999999-2026…"
|
|
49
|
+
upo = client.upo(result.reference) # signed UPO XML — archive this verbatim
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## What works today
|
|
53
|
+
|
|
54
|
+
```ruby
|
|
55
|
+
config = Ksef::Configuration.new(env: :test, timeout: { read: 120 })
|
|
56
|
+
config.base_url # => "https://api-test.ksef.mf.gov.pl/v2"
|
|
57
|
+
config.inspect # credentials are redacted, never logged
|
|
58
|
+
|
|
59
|
+
conn = Ksef::HTTP::Connection.build(config)
|
|
60
|
+
conn.get("rate-limits")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Errors from the API arrive as a typed hierarchy carrying the Ministry's own diagnostics:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
begin
|
|
67
|
+
conn.get("sessions")
|
|
68
|
+
rescue Ksef::RateLimitedError => e
|
|
69
|
+
e.retry_after # => 30 — seconds, from the Retry-After header. Honour it.
|
|
70
|
+
rescue Ksef::AuthorizationError => e
|
|
71
|
+
e.reason_code # => "missing-permissions"
|
|
72
|
+
e.security # => {"requiredAnyOfPermissions" => ["InvoiceWrite"], ...}
|
|
73
|
+
rescue Ksef::ApiError => e
|
|
74
|
+
e.status # => 400
|
|
75
|
+
e.code # => 21405
|
|
76
|
+
e.details # => ["Wskazany kod formularza nie jest wspierany."]
|
|
77
|
+
e.trace_id # quote this to Ministry support
|
|
78
|
+
end
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Environments
|
|
82
|
+
|
|
83
|
+
| Env | Base URL |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `:test` | `https://api-test.ksef.mf.gov.pl/v2` |
|
|
86
|
+
| `:demo` | `https://api-demo.ksef.mf.gov.pl/v2` |
|
|
87
|
+
| `:prod` | `https://api.ksef.mf.gov.pl/v2` |
|
|
88
|
+
|
|
89
|
+
Each URL was verified against that environment's own OpenAPI document; see
|
|
90
|
+
[`docs/REFERENCE.md`](docs/REFERENCE.md). Note the base URL already includes `/v2`.
|
|
91
|
+
`Ksef::Environments.custom(base_url:)` is available for non-public deployments.
|
|
92
|
+
|
|
93
|
+
TEST and DEMO are for integration testing only — never send real invoices or real
|
|
94
|
+
taxpayer data to them, and use random NIPs. TEST data is not isolated between
|
|
95
|
+
integrators.
|
|
96
|
+
|
|
97
|
+
## Ruby support
|
|
98
|
+
|
|
99
|
+
- **MRI >= 3.2**, with **no upper bound, ever.** `required_ruby_version` resolves at
|
|
100
|
+
install time, so an upper bound strands users on each new Ruby release.
|
|
101
|
+
- CI covers 3.2, 3.3, 3.4, 4.0 and `head`, and the full suite is run on 3.2 at every
|
|
102
|
+
milestone — the floor is verified, not just declared.
|
|
103
|
+
- **The 3.2 floor is a commitment, not a default.** Ruby 3.2 is EOL upstream, and this gem
|
|
104
|
+
still supports it deliberately: Polish tax-compliance software upgrades slowly, and 3.2
|
|
105
|
+
is the Rails 8.0 floor. There is no plan to raise it.
|
|
106
|
+
- Later EOL series will be dropped in **minor** releases with a changelog note. Because
|
|
107
|
+
version constraints resolve at install time, users on an older Ruby keep receiving the
|
|
108
|
+
last compatible release.
|
|
109
|
+
- **MRI only.** JRuby and TruffleRuby are untested — the crypto layer needs precise
|
|
110
|
+
OpenSSL RSA-OAEP parameterisation. PRs welcome.
|
|
111
|
+
|
|
112
|
+
## Design notes
|
|
113
|
+
|
|
114
|
+
- **Two decoupled subsystems.** The FA(3) builder has no HTTP dependency and is usable on
|
|
115
|
+
its own; the transport layer accepts anything responding to `#to_xml`, or a raw XML
|
|
116
|
+
string.
|
|
117
|
+
- **`BigDecimal` everywhere for money.** `Float` is forbidden in any monetary path.
|
|
118
|
+
- **Invoice submission is never auto-retried.** A duplicate invoice in KSeF is a real tax
|
|
119
|
+
problem. Idempotent GETs retry with backoff; a failed submission surfaces to you.
|
|
120
|
+
- **Thread-safe.** A single client is shareable across threads (Sidekiq is the expected
|
|
121
|
+
habitat); configuration is frozen at construction.
|
|
122
|
+
- **Secrets never logged.** Tokens, JWTs, symmetric keys and IVs are redacted from
|
|
123
|
+
`#inspect` output.
|
|
124
|
+
|
|
125
|
+
## Roadmap
|
|
126
|
+
|
|
127
|
+
| Version | Scope |
|
|
128
|
+
|---|---|
|
|
129
|
+
| 0.1.0 | KSeF-token auth, crypto, online sessions, send/status/UPO/download, full FA(3) builder for all seven invoice types |
|
|
130
|
+
| 0.2 | Batch sessions, invoice query/search, package export, hardened error catalogue |
|
|
131
|
+
| 0.3 | XAdES authentication, certificate lifecycle, permissions API, offline QR codes |
|
|
132
|
+
| 1.0 | After sustained production use; API stability promise begins |
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
bin/setup # or: bundle install
|
|
138
|
+
bundle exec rake # verify pinned artifacts, specs, RuboCop
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Every externally sourced fact — endpoint paths, XML element names, namespace URIs,
|
|
142
|
+
crypto parameters — is recorded with its source and retrieval date in
|
|
143
|
+
[`docs/REFERENCE.md`](docs/REFERENCE.md). Nothing enters the code without an entry there.
|
|
144
|
+
|
|
145
|
+
## Licence
|
|
146
|
+
|
|
147
|
+
MIT. The bundled FA(3) schemas are published by Ministerstwo Finansów, also under MIT;
|
|
148
|
+
see `lib/ksef/fa3/schema/LICENSE.upstream.txt`.
|
|
149
|
+
|
|
150
|
+
This project is not affiliated with or endorsed by the Polish Ministry of Finance.
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please report security issues privately via GitHub's "Report a vulnerability" flow on
|
|
6
|
+
this repository, rather than opening a public issue. You can expect an acknowledgement
|
|
7
|
+
within a few working days.
|
|
8
|
+
|
|
9
|
+
This gem handles credentials that authenticate against a tax authority, and invoice
|
|
10
|
+
payloads that are legally binding documents. Reports about credential leakage, weakened
|
|
11
|
+
TLS, or incorrect cryptographic parameters are treated as high severity.
|
|
12
|
+
|
|
13
|
+
## Supported versions
|
|
14
|
+
|
|
15
|
+
Security fixes land on the latest minor release.
|
|
16
|
+
|
|
17
|
+
The supported interpreter range is whatever `required_ruby_version` declares — currently
|
|
18
|
+
**MRI >= 3.2**. Note that this **includes Ruby 3.2 even though 3.2 is EOL upstream**: the
|
|
19
|
+
floor is a deliberate commitment (see DESIGN.md §3), so 3.2 users do receive fixes from
|
|
20
|
+
this gem.
|
|
21
|
+
|
|
22
|
+
That said, an EOL interpreter stops receiving fixes for CVEs *in Ruby itself*, which this
|
|
23
|
+
project cannot patch. If you are on 3.2 for compliance reasons, upgrading Ruby is still
|
|
24
|
+
the stronger position.
|
|
25
|
+
|
|
26
|
+
Once a series does fall below the floor in a future minor release, `required_ruby_version`
|
|
27
|
+
resolves at install time, so users on that interpreter stay on the last compatible release
|
|
28
|
+
and stop receiving fixes from us.
|
|
29
|
+
|
|
30
|
+
## Handling of secrets
|
|
31
|
+
|
|
32
|
+
The following must never appear in logs, `#inspect` output, exception messages, or test
|
|
33
|
+
fixtures:
|
|
34
|
+
|
|
35
|
+
- KSeF tokens and JWTs (access and refresh)
|
|
36
|
+
- Session symmetric keys and IVs
|
|
37
|
+
- Full invoice payloads at default log level
|
|
38
|
+
|
|
39
|
+
Enforced by:
|
|
40
|
+
|
|
41
|
+
- A redacting `#inspect` on configuration and authentication objects.
|
|
42
|
+
- VCR cassette scrubbing, plus a spec that scans committed cassettes for `Bearer ` and
|
|
43
|
+
known secret environment values.
|
|
44
|
+
- Integration tests reading credentials only from environment variables
|
|
45
|
+
(`KSEF_TEST_NIP`, `KSEF_TEST_TOKEN`, `KSEF_ENV=test`).
|
|
46
|
+
|
|
47
|
+
## Transport security
|
|
48
|
+
|
|
49
|
+
- TLS verification is always on. No code path may set `VERIFY_NONE`; there is no
|
|
50
|
+
configuration option to disable it.
|
|
51
|
+
- Minimum TLS version is 1.2.
|
|
52
|
+
|
|
53
|
+
## Testing against production
|
|
54
|
+
|
|
55
|
+
The test suite aborts if `KSEF_ENV=prod`, and the nightly workflow fails the same way.
|
|
56
|
+
Never point automated tests at the production environment — invoices submitted there have
|
|
57
|
+
full legal force.
|
|
58
|
+
|
|
59
|
+
## Rate limits
|
|
60
|
+
|
|
61
|
+
KSeF records and analyses rate-limit breaches, and explicitly treats spreading one
|
|
62
|
+
context across many IP addresses as an abuse pattern. This client honours `Retry-After`
|
|
63
|
+
and will never work around a 429 by rotating connections. Please do not add such a
|
|
64
|
+
mechanism.
|
|
65
|
+
|
|
66
|
+
## Publishing
|
|
67
|
+
|
|
68
|
+
Releases use RubyGems Trusted Publishing (OIDC). No long-lived RubyGems API key exists
|
|
69
|
+
for this project. The gemspec sets `rubygems_mfa_required`.
|