@voltro/plugin-sanctions 0.0.0-stage → 0.88.0
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.
- package/CHANGELOG.md +24492 -0
- package/LICENSE +61 -0
- package/README.md +198 -2
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +8333 -0
- package/dist/admission.server.js +96 -0
- package/dist/components.js +282 -0
- package/dist/contract.js +88 -0
- package/dist/entities.js +101 -0
- package/dist/errors.d.ts +13 -0
- package/dist/errors.js +14 -0
- package/dist/eventProducer.d.ts +8 -0
- package/dist/eventProducer.js +19 -0
- package/dist/events.d.ts +14 -0
- package/dist/events.js +10 -0
- package/dist/guard.d.ts +83 -0
- package/dist/guard.js +16 -0
- package/dist/index.d.ts +585 -0
- package/dist/index.js +179 -0
- package/dist/inspect.js +23 -0
- package/dist/port.d.ts +82 -0
- package/dist/port.js +4 -0
- package/dist/rpc.d.ts +165 -0
- package/dist/rpc.js +146 -0
- package/dist/rpcRoutes.js +49 -0
- package/dist/sanctions-app/events/sanctions.changed.event.ts +1 -0
- package/dist/sanctions-app/subscribers/sanctions.actions.subscribe.ts +3 -0
- package/dist/server.d.ts +363 -0
- package/dist/server.js +1 -0
- package/dist/service.js +708 -0
- package/dist/strategies.d.ts +154 -0
- package/dist/strategies.js +72 -0
- package/dist/testing.d.ts +211 -0
- package/dist/testing.js +120 -0
- package/dist/web.d.ts +239 -0
- package/dist/web.js +7 -0
- package/package.json +99 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Voltro — Proprietary Software License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Voltro UG. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and all associated source code, documentation, and other
|
|
6
|
+
materials (the "Software") are the proprietary property of Voltro UG
|
|
7
|
+
("Voltro"). This is NOT open-source software.
|
|
8
|
+
|
|
9
|
+
Your access to and use of the Software is governed exclusively by the Voltro
|
|
10
|
+
Terms of Service at:
|
|
11
|
+
|
|
12
|
+
https://voltro.cloud/legal/terms
|
|
13
|
+
|
|
14
|
+
By downloading, installing, or using the Software you agree to those Terms.
|
|
15
|
+
Subject to and conditioned on your continued compliance with them, Voltro
|
|
16
|
+
grants you a limited, non-exclusive, non-transferable, non-sublicensable,
|
|
17
|
+
revocable license to use the Software. The license covers use by your
|
|
18
|
+
authorised named users only, up to the number of seats (or other billing metric)
|
|
19
|
+
your plan or order covers; each named user must be an identified individual
|
|
20
|
+
using their own personal account, and accounts, access credentials and seats
|
|
21
|
+
must not be shared. All rights not expressly granted in the
|
|
22
|
+
Terms are reserved by Voltro. If you do not agree to the Terms, you have no
|
|
23
|
+
license and may not use the Software.
|
|
24
|
+
|
|
25
|
+
The Terms of Service — including the scope of permitted use, plan
|
|
26
|
+
entitlements, fees, and pricing — may change from time to time. The version in
|
|
27
|
+
force is the one published at the URL above. Commercial terms and pricing are
|
|
28
|
+
NOT part of this notice and are not fixed by, or granted in perpetuity by, the
|
|
29
|
+
version of the Software in which this file appears.
|
|
30
|
+
|
|
31
|
+
Permitted use — your own software. Voltro is a development framework. You may
|
|
32
|
+
use the Software to build, run, and commercially distribute your own
|
|
33
|
+
applications and services, and to charge your own customers for them, without
|
|
34
|
+
owing Voltro any share of that revenue or any further permission beyond the
|
|
35
|
+
Terms. Applications you build with the Software are yours.
|
|
36
|
+
|
|
37
|
+
Prohibited use — reselling Voltro. You may NOT redistribute, resell,
|
|
38
|
+
sublicense, publish, or otherwise provide the Software itself — in whole or in
|
|
39
|
+
part, in source or compiled form — to third parties as a library, framework,
|
|
40
|
+
SDK, template, starter, or development tool for them to build upon, whether
|
|
41
|
+
standalone or repackaged. Shipping the Software as a non-separable, bundled
|
|
42
|
+
dependency inside an application you deliver (for example, compiled into your
|
|
43
|
+
deployed app) is permitted; extracting or re-exposing it as a reusable
|
|
44
|
+
component for others is not.
|
|
45
|
+
|
|
46
|
+
Except as expressly permitted above or by the Terms, you may not copy, modify,
|
|
47
|
+
merge, publish, sublicense, sell, distribute, or create derivative works of the
|
|
48
|
+
Software, in whole or in part.
|
|
49
|
+
|
|
50
|
+
Third-party open-source components distributed alongside the Software are the
|
|
51
|
+
property of their respective owners and are licensed under their own terms; see
|
|
52
|
+
THIRD-PARTY-NOTICES.md where provided. Nothing in this notice limits your
|
|
53
|
+
rights, or extends Voltro's, in those components.
|
|
54
|
+
|
|
55
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
56
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
57
|
+
FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
58
|
+
VOLTRO BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM,
|
|
59
|
+
OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
|
|
60
|
+
|
|
61
|
+
For licensing inquiries, contact Voltro UG.
|
package/README.md
CHANGED
|
@@ -1,3 +1,199 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @voltro/plugin-sanctions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Take
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { sanctionsPlugin } from '@voltro/plugin-sanctions'
|
|
7
|
+
|
|
8
|
+
const plugin = sanctionsPlugin()
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The factory declares seven SQL tables: `_voltro_sanc_reports`,
|
|
12
|
+
`_voltro_sanc_cases`, `_voltro_sanc_actions`, `_voltro_sanc_appeals`,
|
|
13
|
+
`_voltro_sanc_strikes`, `_voltro_sanc_device_hints`, `_voltro_sanc_admissions`.
|
|
14
|
+
SQL owns durable state and successor readback. It contributes eleven typed
|
|
15
|
+
RPCs, eleven client hooks, four rule slots, SanctionsPort, metadata events,
|
|
16
|
+
configuration inspection and user/guest export/erase hooks. There is no Room
|
|
17
|
+
tick I/O or independent Redis connection.
|
|
18
|
+
|
|
19
|
+
Actions are `sanctions.report`, `appeal`, `reviewCase`, `issue`, `revoke`,
|
|
20
|
+
`reviewAppeal`; queries are `sanctions.reportsMine`, `mine`, `appealsMine`,
|
|
21
|
+
`cases`, `appealsQueue`. Human/guest identity and tenant come from the verified
|
|
22
|
+
request. Operator reads/writes require a trusted user/service account carrying
|
|
23
|
+
`sanctions:manage` or `admin:full`; a request payload cannot grant these scopes.
|
|
24
|
+
The operator projection includes evidence references and decision identity;
|
|
25
|
+
player measures include only kind, scope, dates, public reason and appealability.
|
|
26
|
+
Internal reason, issuer, target identity and metadata never appear in that view.
|
|
27
|
+
|
|
28
|
+
A report contains request ID, target, category, bounded context IDs and note.
|
|
29
|
+
It groups into the target's case and is idempotent for the exact intention;
|
|
30
|
+
changed content under the same request ID refuses. **Human reports never call
|
|
31
|
+
the automatic escalation ladder.** The default collector returns no verified
|
|
32
|
+
evidence: a submitted message/replay ID is context, not verified evidence.
|
|
33
|
+
|
|
34
|
+
## Configure
|
|
35
|
+
|
|
36
|
+
| Option | Default | Meaning |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| `maxActiveActions` | 100 | Active measure admission budget per subject |
|
|
39
|
+
| `maxReportsPerCase` | 1,000 | Report budget per case |
|
|
40
|
+
| `maxEvidenceRefs` | 100 | Collected evidence reference budget per case |
|
|
41
|
+
| `maxContextMessageIds` | 41 | Submitted message-context budget |
|
|
42
|
+
| `maxTextLength` | 4,000 code points | Notes/reasons/appeal text limit |
|
|
43
|
+
| `pageSize` | 50 | Raw SQL read page budget |
|
|
44
|
+
| `maxExportRows` | 10,000 | Complete bounded export; overflow refuses |
|
|
45
|
+
| `reportLimit` | 10 | Report attempts per window |
|
|
46
|
+
| `reportWindowMs` | 3,600,000 | Report admission window |
|
|
47
|
+
| `strikeDecayMs` | 2,592,000,000 | Lazy strike expiry window |
|
|
48
|
+
| `minimumSignalConfidence` | 0.99 | Minimum trusted signal confidence for strikes |
|
|
49
|
+
| `rateLimit` | Registry Redis | Existing limiter connection/HotStore options |
|
|
50
|
+
| `strategies` | four defaults | Named rule replacements |
|
|
51
|
+
| `now` | `Date.now` | Clock for rule/observation instants |
|
|
52
|
+
|
|
53
|
+
These are configured budgets, not measured capacity. Report admission uses the
|
|
54
|
+
Registry-backed HotStore limiter. Unbound/fail-open/store-error decisions refuse
|
|
55
|
+
new reports; exact committed retries are read before rate consumption. Borrowed
|
|
56
|
+
HotStore state refuses activation with declared multi-node evidence. A named
|
|
57
|
+
Registry memory transport is a local example and cannot supply cross-node data.
|
|
58
|
+
|
|
59
|
+
Subject admission rows acquire SQL writer admission in deterministic hash order
|
|
60
|
+
before measures, counts and reviews. Case reviews require `baseVersion`.
|
|
61
|
+
Issue intentions retain their receipt after expiry/revocation. An action may be
|
|
62
|
+
permanent or expire; revoked, future and expired rows do not enforce policy.
|
|
63
|
+
Appeals are once per action/owner, preserve exact retry text and allow one
|
|
64
|
+
review outcome; `revoked` also revokes the action transactionally.
|
|
65
|
+
|
|
66
|
+
## Hook
|
|
67
|
+
|
|
68
|
+
`SanctionsPort` from `./port` has four methods: `check(subject, point, context?)`,
|
|
69
|
+
`active(subject)`, `trust(subject)`, `recordSignal(subject, input)`. The SQL
|
|
70
|
+
adapter reads policy afresh. The default matrix applies bans at all points,
|
|
71
|
+
mute/chatBan to chat, matchmakingBan to matchmaking/ranked, rankedBan to ranked,
|
|
72
|
+
tradeBan to trade; shadowBan marks only matchmaking. Channel/queue context
|
|
73
|
+
selects an exact scope. Omitted context conservatively matches restricted scopes.
|
|
74
|
+
Warnings, nameReset and rollback do not themselves execute game mutations.
|
|
75
|
+
|
|
76
|
+
Only System or an explicitly authorized same-tenant service account can submit
|
|
77
|
+
trusted signals. Low-confidence signals stay in review; high-confidence abuse
|
|
78
|
+
signals increment once and use warn → mute 1h → mute 24h → chatBan 7d → ban 30d
|
|
79
|
+
→ permanent ban. Other categories default to review only. Trust uses current
|
|
80
|
+
non-expired strikes; unverified account age/platform/payment facts remain
|
|
81
|
+
unknown. The service does not manufacture those facts.
|
|
82
|
+
|
|
83
|
+
The discovered `sanctions.changed` producer carries only action ID under a
|
|
84
|
+
subject routing key, with `sanctions:events:read` for operator listeners. It
|
|
85
|
+
uses committed tenant evidence and suppresses erased identities. Delivery is
|
|
86
|
+
best-effort. Automatic HotStore policy caching, live auth-cache invalidation,
|
|
87
|
+
Replay/chat evidence collectors and Inbox notification remain integration work.
|
|
88
|
+
|
|
89
|
+
Chat consults the installed port with the actual channel before new sends/edits;
|
|
90
|
+
denial gives `sanctioned`, unavailable policy refuses. An exact already committed
|
|
91
|
+
send retry returns its original receipt. Deletion remains available. Chat without
|
|
92
|
+
the optional port has no sanction policy. This admission is not an atomic
|
|
93
|
+
cross-plugin transaction with a concurrent sanction write.
|
|
94
|
+
|
|
95
|
+
`./guard` exports `sanctionsLoginGuard(service)` for Auth's pre-session guard
|
|
96
|
+
and `sanctionsSubjectGuard(service)` for request-side auth composition. Both use
|
|
97
|
+
the supplied actual check service and refuse unavailability. They are opt-in;
|
|
98
|
+
installing Sanctions alone does not alter an Auth default. A request-side guard
|
|
99
|
+
cached by a host still needs its explicit invalidation integration.
|
|
100
|
+
|
|
101
|
+
## Override
|
|
102
|
+
|
|
103
|
+
`./strategies` exports `abuseEscalationLadder` (`escalationLadder`),
|
|
104
|
+
`conservativeTrustScore` (`trustScore`), `noCollectedSanctionEvidence`
|
|
105
|
+
(`evidenceCollector`), `defaultSanctionEnforcement` (`enforcementPoints`).
|
|
106
|
+
Each default has a real replacement probe in `./testing`.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { sanctionsPlugin } from '@voltro/plugin-sanctions'
|
|
110
|
+
|
|
111
|
+
const plugin = sanctionsPlugin({
|
|
112
|
+
strategies: { escalationLadder: () => null },
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Extend or replace
|
|
117
|
+
|
|
118
|
+
Other systems depend on `./port`, not sanction tables. Install a replacement
|
|
119
|
+
Layer for the four-method port; `fakeSanctionsLayer(overrides)` defaults every
|
|
120
|
+
unimplemented method to `unavailable`, never an implicit allow. The explicit
|
|
121
|
+
`dataStoreSanctions(store, resolveSanctionsOptions(options), limiter)` adapter
|
|
122
|
+
exposes its API/port and trusted device-hint/privacy methods.
|
|
123
|
+
|
|
124
|
+
Device hints require a supplied server-owned random salt of at least 32 bytes;
|
|
125
|
+
the adapter persists only a tenant-bound HMAC. No salt is shipped or read from
|
|
126
|
+
an undeclared env name. The template does not collect hints. Hints are evidence
|
|
127
|
+
for review, never a hardware-ban guarantee.
|
|
128
|
+
|
|
129
|
+
Export selects bounded exact tenant/subject references across all seven tables.
|
|
130
|
+
Erase removes device/strike rows, redacts reports, evidence, reasons and appeal
|
|
131
|
+
text, revokes the erased target's measures, retains peers and leaves a redacted
|
|
132
|
+
admission tombstone. Sorted writer fences cover subject and related targets;
|
|
133
|
+
a changed reference set retries before redaction. Erased identity cannot create
|
|
134
|
+
new measures/reports/signals and check refuses it. Reactivation, identity merge,
|
|
135
|
+
namespace/mixins, custom-column query/UI propagation and stack removal remain open.
|
|
136
|
+
|
|
137
|
+
## Panel and GM
|
|
138
|
+
|
|
139
|
+
The server `/status`, shared SanctionsPage, Local read-token provider and Cloud
|
|
140
|
+
authorized-app/replica proxy display configuration, slots, limiter activation
|
|
141
|
+
and store binding. They do not enumerate cases or claim backend health/capacity.
|
|
142
|
+
The operator RPC queue/review actions are written. Full GM evidence views,
|
|
143
|
+
history, audit receipts, governed bulk approval and replay scrubber remain open;
|
|
144
|
+
install `plugin-audit` with its durable sink for the framework RPC audit path.
|
|
145
|
+
|
|
146
|
+
`./web` provides ReportDialog, SanctionNotice and AppealDialog with EN/DE labels.
|
|
147
|
+
They render escaped public text, scope-fence stale observations and keep drafts,
|
|
148
|
+
request IDs and uncertain pending writes in the parent. No component automatically
|
|
149
|
+
replays a request or discards a draft. Presence/profile/Chat report wiring remains
|
|
150
|
+
for the composed frontend template.
|
|
151
|
+
|
|
152
|
+
## Tests
|
|
153
|
+
|
|
154
|
+
Written fixtures cover the default kind × point matrix, scoped/future/expired/
|
|
155
|
+
revoked decisions, human/trusted separation, rates, exact receipts, one appeal,
|
|
156
|
+
case versions, replacement slots/port, opt-in guards, device redaction and
|
|
157
|
+
privacy. `systemContractConformance` registers all slots/port/events, inspect
|
|
158
|
+
and user/guest hooks for all seven tables. Five native cases per six dialects
|
|
159
|
+
cover round trips, two-pool admission/versioning and successor privacy; missing
|
|
160
|
+
native configuration refuses the fixture rather than skipping acceptance. No
|
|
161
|
+
Scheduled Run number, budget or support claim is inferred from file existence.
|
|
162
|
+
|
|
163
|
+
## Prepared SQL permission admission
|
|
164
|
+
|
|
165
|
+
`SanctionsPlugin.sanctions.admission()` returns a server-only
|
|
166
|
+
`SanctionsSqlAdmissionService` with `read(subject, { point, at, context? })` and
|
|
167
|
+
`prepare(subject, { point, at, context?, expected })`. The app supplies captured
|
|
168
|
+
server time; there is no player RPC accepting time or permission facts. `read`
|
|
169
|
+
returns actual `allowed` and strike-derived `trustScore`. It borrows the existing
|
|
170
|
+
seven SQL roles and the same active-measure, trust and enforcement rules; missing
|
|
171
|
+
verified account/payment facts receive no invented bonus. The ordinary four-method
|
|
172
|
+
`SanctionsPort` stays unchanged.
|
|
173
|
+
|
|
174
|
+
The service reads a complete bounded action/strike snapshot under the owning
|
|
175
|
+
SQL subject fence. Pure trust/enforcement slots run after that snapshot
|
|
176
|
+
transaction ends. `prepare` checks the expected permission and returns an
|
|
177
|
+
exact-store `PreparedSqlMutation<void>`. Its acceptance locks the same subject
|
|
178
|
+
fence and compares actual SQL records with the captured fingerprint. A changed
|
|
179
|
+
measure, strike or erased identity refuses; the whole enclosing asset group
|
|
180
|
+
rolls back. Clock, slots and external reads do not run in this replayable commit.
|
|
181
|
+
The installed wrapper revokes escaped prepared capabilities after deactivation.
|
|
182
|
+
No new table, automatic trade permission, consent/age record or player state
|
|
183
|
+
endpoint is introduced. The owning policy's configured work bounds remain budgets.
|
|
184
|
+
|
|
185
|
+
The four configuration inspect layers expose `atomicAdmissionInstalled:true`;
|
|
186
|
+
binding state remains separate. This declares a capability, not successful
|
|
187
|
+
runtime enforcement or SQL health.
|
|
188
|
+
|
|
189
|
+
`prepareMany({ tenantId, point, at, context?, participants })` prepares one
|
|
190
|
+
complete permission unit for multiple expected owner facts, with a configured
|
|
191
|
+
32-participant budget. All subject fences follow the owning SQL adapter's same
|
|
192
|
+
canonical order in snapshot and commit. `prepare` delegates its single
|
|
193
|
+
participant to that same path. The Trade adapter uses this batch capability for
|
|
194
|
+
both parties, so reversed trades do not choose competing participant lock
|
|
195
|
+
orders. Duplicate, oversized, sparse or accessor-owned inputs refuse.
|
|
196
|
+
|
|
197
|
+
Production activation now source-checks the actual deployment-wide plugin grant.
|
|
198
|
+
Declare actual Licensing first; development/test remains free. See the bilingual
|
|
199
|
+
Licensing contract and manual update migration.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
We take the security of Voltro and the applications built on it seriously. This
|
|
4
|
+
document explains how to report a vulnerability and what to expect in return.
|
|
5
|
+
|
|
6
|
+
## Reporting a vulnerability
|
|
7
|
+
|
|
8
|
+
**Please do not open public issues or discuss suspected vulnerabilities in
|
|
9
|
+
public channels.** Report them privately by email:
|
|
10
|
+
|
|
11
|
+
**security contact: [support@voltro.dev](mailto:support@voltro.dev)**
|
|
12
|
+
(subject line: `SECURITY`).
|
|
13
|
+
|
|
14
|
+
Include, where you can:
|
|
15
|
+
|
|
16
|
+
- the affected package(s) and version(s) (e.g. `@voltro/runtime@x.y.z`);
|
|
17
|
+
- a description of the issue and its impact;
|
|
18
|
+
- a minimal reproduction or proof of concept;
|
|
19
|
+
- any suggested remediation.
|
|
20
|
+
|
|
21
|
+
If you'd like to encrypt your report, ask in a first plain email and we'll
|
|
22
|
+
arrange a key.
|
|
23
|
+
|
|
24
|
+
## What to expect
|
|
25
|
+
|
|
26
|
+
- **Acknowledgement** of your report within **3 business days**.
|
|
27
|
+
- An initial assessment (severity, affected surface) and a remediation plan as
|
|
28
|
+
soon as we've reproduced the issue.
|
|
29
|
+
- **Coordinated disclosure:** we'll agree a disclosure timeline with you and
|
|
30
|
+
credit you in the release notes if you wish. Please give us reasonable time to
|
|
31
|
+
ship a fix before any public disclosure.
|
|
32
|
+
|
|
33
|
+
We do not currently run a paid bug-bounty program, but we genuinely appreciate
|
|
34
|
+
responsible disclosure and will credit reporters.
|
|
35
|
+
|
|
36
|
+
## Software Bill of Materials (SBOM)
|
|
37
|
+
|
|
38
|
+
A CycloneDX SBOM of the third-party runtime dependency graph is generated for the
|
|
39
|
+
published packages (`pnpm gen:sbom` → `sbom.cdx.json`). If your procurement or
|
|
40
|
+
security team needs it, request it at
|
|
41
|
+
[support@voltro.dev](mailto:support@voltro.dev).
|
|
42
|
+
|
|
43
|
+
## Supported versions
|
|
44
|
+
|
|
45
|
+
Voltro is pre-1.0 and ships in lockstep: **only the latest published minor of
|
|
46
|
+
each `@voltro/*` package receives security fixes.** Please upgrade to the latest
|
|
47
|
+
release before reporting, and pin exact versions in production.
|
|
48
|
+
|
|
49
|
+
## Scope
|
|
50
|
+
|
|
51
|
+
In scope: the published `@voltro/*` packages and the framework's own code.
|
|
52
|
+
|
|
53
|
+
Out of scope: vulnerabilities in third-party dependencies that are already
|
|
54
|
+
tracked upstream (we monitor these via a production-dependency audit gate in
|
|
55
|
+
CI), and issues that require a non-default, explicitly-unsafe configuration. If
|
|
56
|
+
you're unsure, report it anyway — we'd rather hear about it.
|