Compare commits
14
Commits
b89edfafa9
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54141e9ccb | ||
|
|
2957524af9 | ||
|
|
28478cf5fe | ||
|
|
fb7f13f0ab | ||
|
|
67378bd193 | ||
|
|
99a1e3e07d | ||
|
|
ceef6b11b2 | ||
|
|
0400b12566 | ||
|
|
4efa617e25 | ||
|
|
fece516828 | ||
|
|
ee7b4c5404 | ||
|
|
c96e61e526 | ||
|
|
97ae23e1f2 | ||
|
|
bb9b00295f |
@@ -14,6 +14,13 @@ jobs:
|
||||
node-version: 22
|
||||
- name: Validate repository documentation
|
||||
run: test -f README.md && test -f AGENTS.md && test -f docs/versioning.md
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- name: Validate restored-session schema and negative cases
|
||||
run: |
|
||||
python -m pip install jsonschema==4.26.0
|
||||
python tests/session_contract.py
|
||||
- name: Validate JSON contracts and fixtures
|
||||
run: |
|
||||
node --input-type=module <<'NODE'
|
||||
|
||||
@@ -4,6 +4,10 @@ Shared versioned HTTP and authenticated WebSocket contracts for `trixie-server`
|
||||
|
||||
This repository contains schemas, shared enums, error codes, compatibility fixtures, contract tests, and API documentation only.
|
||||
|
||||
The API repository is the boundary between the server authority and the Linux
|
||||
client presentation layer. It contains no Twitch credentials, database logic,
|
||||
or UI behavior.
|
||||
|
||||
The first contract slice is under `contracts/v1/` and `fixtures/v1/`. It covers
|
||||
server readiness, health, errors, and the transport-neutral realtime event
|
||||
envelope so the client and server can be developed and tested together before
|
||||
@@ -12,9 +16,41 @@ request and response envelopes; bearer values in fixtures are synthetic only.
|
||||
Twitch OAuth link and completion response envelopes are also versioned here;
|
||||
fixtures contain no real credentials or tokens.
|
||||
|
||||
`GET /api/v1/auth/session` returns `authenticated: true` and the current
|
||||
`must_replace_credentials` flag from the administrator account. Restoring a
|
||||
session must not bypass first-run setup. Older servers omit this flag; clients
|
||||
must not interpret an absent flag as completed credential replacement.
|
||||
|
||||
The shared boundary vocabulary includes the ordered permission levels in
|
||||
`contracts/v1/permissions.json` and the client/server compatibility result in
|
||||
`contracts/v1/version-negotiation.json`. Server-owned state is delivered as
|
||||
the authenticated `realtime-event.json` envelope; clients must ignore event
|
||||
types they do not understand.
|
||||
|
||||
Guest Star channel settings are described by
|
||||
`contracts/v1/guest-star-channel-settings-response.json`. The browser-source
|
||||
token is a server-to-authenticated-client value and fixtures use a synthetic
|
||||
placeholder only.
|
||||
|
||||
The Twitch-authoritative collaboration capability probe is described by
|
||||
`collaboration-capabilities-response.json`; unavailable beta surfaces include
|
||||
a machine-readable reason without exposing Twitch tokens.
|
||||
|
||||
Destructive backup recovery uses the explicit `backup-restore-request.json`
|
||||
and `backup-restore-response.json` contracts; test fixtures contain no real
|
||||
database paths or credentials.
|
||||
|
||||
The authenticated WebAssembly plugin lifecycle uses the manifest, install,
|
||||
installed-response, and plugin-secret-binding-request contracts. Fixtures
|
||||
contain only synthetic package metadata and no executable module or secret.
|
||||
|
||||
Command simulation uses `bot-command-simulate-request.json` and
|
||||
`bot-command-simulate-response.json`. A sample response is the default and
|
||||
real network requests require an explicit `use_real_request` flag; fixtures
|
||||
contain only local synthetic data.
|
||||
|
||||
Named-user command rules use `bot-command-user-rule.json`; fixtures contain
|
||||
only synthetic Twitch IDs and literal response templates.
|
||||
|
||||
Typed command arguments use `bot-command-argument-definition.json` and remain
|
||||
literal validated data.
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
"title": "Trixie Session Response",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["authenticated"],
|
||||
"required": ["authenticated", "must_replace_credentials"],
|
||||
"properties": {
|
||||
"authenticated": { "const": true }
|
||||
"authenticated": { "const": true },
|
||||
"must_replace_credentials": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/backup-restore-request.json",
|
||||
"title": "Backup restore request",
|
||||
"type": "object",
|
||||
"required": ["filename", "confirmation"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"pattern": "^trixie-[A-Za-z0-9T_.-]+\\.dump$",
|
||||
"maxLength": 128
|
||||
},
|
||||
"confirmation": { "const": "RESTORE" },
|
||||
"emergency_override": { "type": "boolean", "default": false }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/backup-restore-response.json",
|
||||
"title": "Backup restore response",
|
||||
"type": "object",
|
||||
"required": ["status", "filename", "reason"],
|
||||
"properties": {
|
||||
"status": { "type": "string", "enum": ["ok", "failed"] },
|
||||
"filename": { "type": "string" },
|
||||
"reason": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.invalid/contracts/v1/bot-command-argument-definition.json",
|
||||
"title": "Trixie typed bot command argument",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "kind", "required"],
|
||||
"properties": {
|
||||
"name": { "type": "string", "pattern": "^[A-Za-z0-9_]{1,64}$" },
|
||||
"kind": { "enum": ["text", "number", "choice", "username", "duration"] },
|
||||
"required": { "type": "boolean" },
|
||||
"default": { "type": ["string", "null"], "maxLength": 200 },
|
||||
"minimum": { "type": ["integer", "null"] },
|
||||
"maximum": { "type": ["integer", "null"] },
|
||||
"choices": { "type": "array", "maxItems": 64, "items": { "type": "string", "minLength": 1, "maxLength": 200 } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.invalid/contracts/v1/bot-command-simulate-request.json",
|
||||
"title": "Trixie bot command simulation request",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["template"],
|
||||
"properties": {
|
||||
"template": { "type": "string", "minLength": 1, "maxLength": 2000 },
|
||||
"variables": { "type": "object", "additionalProperties": { "type": "string", "maxLength": 2000 } },
|
||||
"web_request": { "type": ["object", "null"] },
|
||||
"sample_response": {},
|
||||
"use_real_request": { "type": "boolean", "default": false },
|
||||
"response_fields": {
|
||||
"type": "array",
|
||||
"maxItems": 128,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"prefixItems": [
|
||||
{ "type": "string", "minLength": 1, "maxLength": 64 },
|
||||
{ "type": "string", "minLength": 1, "maxLength": 256 }
|
||||
],
|
||||
"items": false,
|
||||
"minItems": 2,
|
||||
"maxItems": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.invalid/contracts/v1/bot-command-simulate-response.json",
|
||||
"title": "Trixie bot command simulation response",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["status", "extracted_variables"],
|
||||
"properties": {
|
||||
"status": { "const": "ok" },
|
||||
"rendered": { "type": ["string", "null"], "maxLength": 2000 },
|
||||
"extracted_variables": { "type": "object", "additionalProperties": { "type": "string" } },
|
||||
"error": { "type": ["string", "null"], "maxLength": 500 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.invalid/contracts/v1/bot-command-user-rule.json",
|
||||
"title": "Trixie named-user command rule",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["user_id"],
|
||||
"properties": {
|
||||
"user_id": { "type": "string", "pattern": "^[0-9]{1,64}$" },
|
||||
"response_template": { "type": ["string", "null"], "minLength": 1, "maxLength": 2000 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/collaboration-capabilities-response.json",
|
||||
"title": "Collaboration capabilities response",
|
||||
"type": "object",
|
||||
"required": ["guest_star_available", "shared_chat_available"],
|
||||
"properties": {
|
||||
"guest_star_available": { "type": "boolean" },
|
||||
"guest_star_reason": { "type": ["string", "null"] },
|
||||
"shared_chat_available": { "type": "boolean" },
|
||||
"shared_chat_reason": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -14,10 +14,26 @@
|
||||
"properties": {
|
||||
"user_id": { "type": "string" },
|
||||
"user_display_name": { "type": ["string", "null"] },
|
||||
"user_login": { "type": ["string", "null"] },
|
||||
"slot_id": { "type": ["string", "null"] },
|
||||
"is_live": { "type": ["boolean", "null"] }
|
||||
"is_live": { "type": ["boolean", "null"] },
|
||||
"volume": { "type": ["integer", "null"], "minimum": 0, "maximum": 100 },
|
||||
"assigned_at": { "type": ["string", "null"], "format": "date-time" },
|
||||
"audio_settings": { "$ref": "#/$defs/media_settings" },
|
||||
"video_settings": { "$ref": "#/$defs/media_settings" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"media_settings": {
|
||||
"type": ["object", "null"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"is_host_enabled": { "type": ["boolean", "null"] },
|
||||
"is_guest_enabled": { "type": ["boolean", "null"] },
|
||||
"is_available": { "type": ["boolean", "null"] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/guest-star-channel-settings-response.json",
|
||||
"title": "Guest Star channel settings response",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"is_moderator_send_live_enabled",
|
||||
"slot_count",
|
||||
"is_browser_source_audio_enabled",
|
||||
"group_layout",
|
||||
"browser_source_token"
|
||||
],
|
||||
"properties": {
|
||||
"is_moderator_send_live_enabled": { "type": "boolean" },
|
||||
"slot_count": { "type": "integer", "minimum": 1, "maximum": 6 },
|
||||
"is_browser_source_audio_enabled": { "type": "boolean" },
|
||||
"group_layout": {
|
||||
"type": "string",
|
||||
"enum": ["TILED_LAYOUT", "SCREENSHARE_LAYOUT", "HORIZONTAL_LAYOUT", "VERTICAL_LAYOUT"]
|
||||
},
|
||||
"browser_source_token": { "type": "string", "minLength": 1 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/guest-star-invites-response.json",
|
||||
"title": "Guest Star invites response",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["user_id", "invited_at", "status", "is_video_enabled", "is_audio_enabled"],
|
||||
"properties": {
|
||||
"user_id": { "type": "string", "minLength": 1 },
|
||||
"invited_at": { "type": "string", "format": "date-time" },
|
||||
"status": { "type": "string", "enum": ["INVITED", "ACCEPTED", "READY"] },
|
||||
"is_video_enabled": { "type": "boolean" },
|
||||
"is_audio_enabled": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,16 @@
|
||||
"title": "Trixie public overlay",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["slug", "html", "css", "javascript", "enabled", "disabled_design"],
|
||||
"required": ["slug", "html", "css", "javascript", "enabled", "disabled_design", "alert_group_window_ms", "alert_group_size", "alert_display_ms"],
|
||||
"properties": {
|
||||
"slug": { "type": "string", "pattern": "^[a-z0-9-]+$" },
|
||||
"html": { "type": "string" },
|
||||
"css": { "type": "string" },
|
||||
"javascript": { "type": "string" },
|
||||
"enabled": { "type": "boolean" },
|
||||
"disabled_design": { "type": "string" }
|
||||
"disabled_design": { "type": "string" },
|
||||
"alert_group_window_ms": { "type": "integer", "minimum": 0, "maximum": 5000 },
|
||||
"alert_group_size": { "type": "integer", "minimum": 1, "maximum": 20 },
|
||||
"alert_display_ms": { "type": "integer", "minimum": 500, "maximum": 60000 }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/plugin-install-request.json",
|
||||
"title": "Plugin install request",
|
||||
"type": "object",
|
||||
"required": ["manifest", "wasm_base64"],
|
||||
"properties": {
|
||||
"manifest": { "$ref": "plugin-manifest.json" },
|
||||
"wasm_base64": { "type": "string", "minLength": 1, "maxLength": 5592406 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/plugin-installed-response.json",
|
||||
"title": "Installed plugin response",
|
||||
"type": "object",
|
||||
"required": ["id", "plugin_id", "name", "version", "manifest", "enabled", "installed_at", "updated_at"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "format": "uuid" },
|
||||
"plugin_id": { "type": "string" },
|
||||
"name": { "type": "string" },
|
||||
"version": { "type": "string" },
|
||||
"manifest": { "$ref": "plugin-manifest.json" },
|
||||
"enabled": { "type": "boolean" },
|
||||
"installed_at": { "type": "string" },
|
||||
"updated_at": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/plugin-manifest.json",
|
||||
"title": "Trixie WebAssembly plugin manifest",
|
||||
"type": "object",
|
||||
"required": ["id", "name", "version", "api_version", "permissions", "entrypoint"],
|
||||
"properties": {
|
||||
"id": { "type": "string", "pattern": "^[a-z0-9.-]+$", "maxLength": 64 },
|
||||
"name": { "type": "string", "minLength": 1, "maxLength": 128 },
|
||||
"version": { "type": "string", "minLength": 1, "maxLength": 64 },
|
||||
"api_version": { "type": "string", "maxLength": 32 },
|
||||
"permissions": { "type": "array", "maxItems": 16, "items": { "enum": ["chat.read", "chat.send", "overlay.emit", "twitch.read", "twitch.manage"] } },
|
||||
"required_secrets": { "type": "array", "maxItems": 16, "items": { "type": "string", "pattern": "^[A-Za-z0-9_]{1,100}$" } },
|
||||
"entrypoint": { "type": "string", "minLength": 1, "maxLength": 64 }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://trixie.local/contracts/v1/plugin-secret-binding-request.json",
|
||||
"title": "Plugin secret binding request",
|
||||
"type": "object",
|
||||
"required": ["secret_name", "approved"],
|
||||
"properties": {
|
||||
"secret_name": { "type": "string", "pattern": "^[A-Za-z0-9_]{1,100}$" },
|
||||
"approved": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
@@ -16,3 +16,11 @@ than in a URL query parameter. The server closes the connection when the frame
|
||||
is missing, malformed, or invalid, and sends `connection.ready` only after
|
||||
successful validation.
|
||||
|
||||
The restored-session contract has Draft 2020-12 validation for both credential
|
||||
replacement states, missing fields, wrong types, and unexpected properties:
|
||||
|
||||
```sh
|
||||
uv run --with jsonschema==4.26.0 python tests/session_contract.py
|
||||
```
|
||||
|
||||
This isolated validation dependency is tooling only, not an application dependency.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"authenticated": true
|
||||
"authenticated": true,
|
||||
"must_replace_credentials": false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"authenticated": true,
|
||||
"must_replace_credentials": true
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"filename": "trixie-20261025T030000Z.dump",
|
||||
"reason": null
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "count",
|
||||
"kind": "number",
|
||||
"required": true,
|
||||
"default": null,
|
||||
"minimum": 1,
|
||||
"maximum": 5,
|
||||
"choices": []
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"template": "Hello ${user_name}; status=${status}",
|
||||
"variables": { "user_name": "PreviewUser" },
|
||||
"sample_response": { "status": "ok" },
|
||||
"use_real_request": false,
|
||||
"response_fields": [["status", "$.status"]]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"status": "ok",
|
||||
"rendered": "Hello PreviewUser; status=ok",
|
||||
"extracted_variables": { "status": "ok" },
|
||||
"error": null
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"user_id": "123456789",
|
||||
"response_template": "Welcome back, ${user_name}!"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"guest_star_available": true,
|
||||
"guest_star_reason": null,
|
||||
"shared_chat_available": true,
|
||||
"shared_chat_reason": null
|
||||
}
|
||||
@@ -1,4 +1,24 @@
|
||||
{
|
||||
"id": "guest-star-session-1",
|
||||
"guests": []
|
||||
"guests": [
|
||||
{
|
||||
"user_id": "123456",
|
||||
"user_display_name": "GuestOne",
|
||||
"user_login": "guestone",
|
||||
"slot_id": "1",
|
||||
"is_live": true,
|
||||
"volume": 85,
|
||||
"assigned_at": "2026-10-25T12:01:00Z",
|
||||
"audio_settings": {
|
||||
"is_host_enabled": true,
|
||||
"is_guest_enabled": true,
|
||||
"is_available": true
|
||||
},
|
||||
"video_settings": {
|
||||
"is_host_enabled": true,
|
||||
"is_guest_enabled": false,
|
||||
"is_available": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"is_moderator_send_live_enabled": true,
|
||||
"slot_count": 4,
|
||||
"is_browser_source_audio_enabled": false,
|
||||
"group_layout": "TILED_LAYOUT",
|
||||
"browser_source_token": "fixture-token-never-use"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"user_id": "144601104",
|
||||
"invited_at": "2026-10-25T12:00:00Z",
|
||||
"status": "READY",
|
||||
"is_video_enabled": true,
|
||||
"is_audio_enabled": false
|
||||
}
|
||||
]
|
||||
@@ -4,5 +4,8 @@
|
||||
"css": "#alert { color: white; }",
|
||||
"javascript": "",
|
||||
"enabled": true,
|
||||
"disabled_design": "transparent"
|
||||
"disabled_design": "transparent",
|
||||
"alert_group_window_ms": 200,
|
||||
"alert_group_size": 5,
|
||||
"alert_display_ms": 4000
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"id": "00000000-0000-4000-8000-000000000001",
|
||||
"plugin_id": "example.plugin",
|
||||
"name": "Example",
|
||||
"version": "1.0.0",
|
||||
"manifest": {
|
||||
"id": "example.plugin",
|
||||
"name": "Example",
|
||||
"version": "1.0.0",
|
||||
"api_version": "v1",
|
||||
"permissions": ["chat.read"],
|
||||
"entrypoint": "trixie_start"
|
||||
},
|
||||
"enabled": true,
|
||||
"installed_at": "2026-10-25T00:00:00Z",
|
||||
"updated_at": "2026-10-25T00:00:00Z"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"secret_name": "VTS_API_TOKEN",
|
||||
"approved": true
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
"""Validate restored-session fixtures and rejection cases against Draft 2020-12."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from jsonschema import Draft202012Validator
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
schema = json.loads((root / "contracts/v1/auth-session-response.json").read_text())
|
||||
Draft202012Validator.check_schema(schema)
|
||||
validator = Draft202012Validator(schema)
|
||||
|
||||
for name in ["auth-session.authenticated.json", "auth-session.bootstrap.json"]:
|
||||
validator.validate(json.loads((root / "fixtures/v1" / name).read_text()))
|
||||
|
||||
for invalid in [
|
||||
{"authenticated": True},
|
||||
{"authenticated": False, "must_replace_credentials": False},
|
||||
{"authenticated": True, "must_replace_credentials": "false"},
|
||||
{"authenticated": True, "must_replace_credentials": False, "unexpected": True},
|
||||
]:
|
||||
assert not validator.is_valid(invalid), "Invalid session response was accepted"
|
||||
|
||||
print("Session schema: two valid fixtures and four rejection cases passed")
|
||||
Reference in New Issue
Block a user