SecaniDokumentation

Validierungs-API

OSCAL-1.2.2-JSON-Dokumente per HTTP validieren – zustandslos, anonym oder mit API-Schlüssel, mit derselben Engine wie der Browser-Validator.

Die Secani OSCAL Validierungs-API validiert OSCAL-1.2.2-JSON-Dokumente per HTTP. Sende das Dokument selbst als Request-Body per POST – ohne Umschlag, ohne Konto – und erhalte einen maschinenlesbaren Bericht von derselben Engine, die auch den Browser-Validator antreibt. Die API ist für Maschinen im Arbeitsfluss gebaut: CI-Jobs, Integrationsskripte und andere Werkzeuge, die OSCAL-Dokumente erzeugen oder transformieren.

Datenschutz-Zusage. Dein Dokument wird flüchtig im Arbeitsspeicher auf EU-Servern (Frankfurt) verarbeitet und mit dem Senden der Antwort verworfen. Nichts wird gespeichert, protokolliert oder für etwas anderes als die Antwort verwendet; Telemetrie ist ausschließlich aggregiert (Modelltyp, Größenklasse, Ergebnis, Dauer). Der Browser-Validator bleibt vollständig browser-lokal – dort verlässt dein Dokument den Browser nie.

Schnellstart

curl -sS -X POST https://secani.com/api/oscal/v1/validate \
  -H "content-type: application/json" \
  --data-binary @system-security-plan.json

Große Artefakte (vollständige Catalogs können das 4-MB-Limit für unkomprimierte Bodies überschreiten) lassen sich hervorragend komprimieren – sende sie gezippt:

gzip -c catalog.json | curl -sS -X POST https://secani.com/api/oscal/v1/validate \
  -H "content-type: application/json" \
  -H "content-encoding: gzip" \
  --data-binary @-

Antwort

Eine abgeschlossene Validierung liefert immer HTTP 200 – "valid": false ist die erfolgreiche Validierung eines ungültigen Dokuments. Verzweige auf dem Feld valid, nicht auf dem Statuscode.

{
  "valid": false,
  "model": "system-security-plan",
  "oscalVersion": "1.2.2",
  "level": "schema",
  "complete": true,
  "issues": [
    {
      "ruleId": "nist-schema:1.2.2:system-security-plan:required:system-security-plan/metadata/version:required",
      "path": "/system-security-plan/metadata/version",
      "message": "must have required property 'version'",
      "keyword": "required",
      "severity": "error"
    }
  ],
  "issueCount": 37,
  "truncated": false,
  "meta": {
    "engine": "@secani/oscal",
    "validator": "1.2.2",
    "schemaSource": "NIST OSCAL v1.2.2 release JSON schemas",
    "patches": ["profile-combine-method"],
    "durationMs": 84
  }
}
FeldBedeutung
validOb das Dokument ohne error-Feststellungen gültig ist. warning-Feststellungen machen es nicht false.
modelErkanntes OSCAL-Modell (eines der acht OSCAL-1.2.2-Modelle).
oscalVersionDie im Metadaten-Block deklarierte oscal-version; unknown, wenn sie fehlt.
levelAusgeführte Validierungsstufe: schema (Standard) oder full (siehe Validierungsstufen).
completetrue, wenn jede angeforderte Stufe für ein erkanntes Modell vollständig durchlief.
issues[].ruleIdStabile ID der Regel, die die Feststellung erzeugt hat, schema-abgeleitet oder semantisch.
issues[].pathRFC-6901-JSON-Pointer in das eingereichte Dokument.
issues[].severityerror oder warning; warning ist beratend und macht valid nicht false.
issueCountTatsächliche Gesamtzahl der Feststellungen, auch wenn issues gekürzt ist.
truncatedtrue, wenn mehr als 200 Feststellungen gefunden und die Liste gekappt wurde.
meta.validatorOSCAL-Release, auf das die vorkompilierten Validatoren zielen (aktuell 1.2.2).
meta.patchesDokumentierte Abweichungen von den rohen NIST-Release-Schemas.

Fehler

Fehler verwenden RFC-9457-Problem-Details (application/problem+json) mit einem stabilen maschinenlesbaren code:

Jedes Problem enthält außerdem einen konkreten Hinweis in resolution und eine documentation-URL. Die vollständige Referenz steht unter API-Fehler beheben.

StatusCodeBedeutung
400ERR_INVALID_JSONDer Body ist kein wohlgeformtes JSON.
400ERR_INVALID_UTF8Der Body ist kein gültiges UTF-8.
400ERR_UNKNOWN_MODELJSON, aber kein erkennbares OSCAL-Wurzelmodell.
400ERR_INVALID_CONTENT_ENCODINGContent-Encoding: gzip deklariert, aber der Body ist kein gültiges gzip.
400ERR_UNSUPPORTED_PARAMETEREin Query-Parameter trägt einen ungültigen oder nicht unterstützten Wert (etwa eine unbekannte rules-ID).
401ERR_INVALID_API_KEYDer präsentierte API-Schlüssel ist unbekannt oder widerrufen.
405ERR_METHOD_NOT_ALLOWEDNur POST (und OPTIONS) werden akzeptiert.
413ERR_PAYLOAD_TOO_LARGEUnkomprimierter Body über 4 MB oder dekomprimierter Body über 24 MB.
415ERR_UNSUPPORTED_MEDIA_TYPEAnderer Content-Type als application/json oder ein nicht unterstütztes Encoding.
429ERR_RATE_LIMITEDRate-Limit überschritten; siehe Retry-After.
500ERR_INTERNALUnerwarteter Fehler; es werden keine Interna offengelegt.
503ERR_KEY_SERVICE_UNAVAILABLEDie Schlüsselprüfung ist vorübergehend nicht erreichbar; siehe Retry-After.

Validierungsstufen

Der Query-Parameter level steuert die Prüftiefe. Ohne Angabe läuft level=schema – reine JSON-Schema-Validierung, unverändert. level=full schaltet zusätzlich die semantische Schicht dazu: Constraint- und Referenzprüfungen, die über das hinausgehen, was das JSON-Schema allein ausdrücken kann.

curl -sS -X POST "https://secani.com/api/oscal/v1/validate?level=full" \
  -H "content-type: application/json" \
  --data-binary @catalog.json

Ein full-Lauf, der die semantische Schicht tatsächlich erreicht, kann Feststellungen mit severity: "warning" liefern. warning-Feststellungen sind beratend und machen ein Dokument nicht ungültig: Sie melden fragwürdige, aber nicht schema-verletzende Muster (etwa einen internen Link, der ins Leere zeigt), und valid bleibt true. Verzweige weiterhin auf valid; severity trennt dann Fehler von Hinweisen.

{
  "valid": true,
  "model": "catalog",
  "oscalVersion": "1.2.2",
  "level": "full",
  "complete": true,
  "issues": [
    {
      "ruleId": "CAT-002.a",
      "path": "/catalog/controls/0/links/0/href",
      "message": "local catalog link '#missing-part' does not resolve to a control, part, or resource",
      "keyword": "resolved-catalog-link",
      "severity": "warning"
    }
  ],
  "issueCount": 1,
  "truncated": false,
  "meta": {
    "engine": "@secani/oscal",
    "validator": "1.2.2",
    "schemaSource": "NIST OSCAL v1.2.2 release JSON schemas",
    "patches": ["profile-combine-method"],
    "durationMs": 112,
    "semanticRules": {
      "count": 30,
      "sha256": "d5e9ef745394fed06db58bcd5999c505cbccc83e460db024b6f3061cb710d213"
    }
  }
}

Standardmäßig deaktivierte Regeln schaltest du einzeln über rules= zu – eine kommagetrennte Liste von Regel-IDs, nur zusammen mit level=full gültig. Eine unbekannte ID liefert 400 ERR_UNSUPPORTED_PARAMETER und nennt die betreffende ID, ohne den Regelkatalog auszuschütten:

curl -sS -X POST "https://secani.com/api/oscal/v1/validate?level=full&rules=PROF-002.a" \
  -H "content-type: application/json" \
  --data-binary @profile.json

Jeder full-Lauf, der die semantische Schicht erreicht, meldet meta.semanticRules: die Anzahl der aktiven semantischen Regeln (count) und einen stabilen SHA-256 über die sortierte Menge ihrer IDs (sha256). Ein full-Lauf, der bereits an der Schema-Schicht scheitert, erreicht die Semantik nicht und enthält daher kein meta.semanticRules. Der Hash identifiziert exakt, welches Regelwerk angewandt wurde; schaltest du über rules= eine Regel zu, ändert er sich. Eine gespeicherte Antwort wird damit zu einem reproduzierbaren Nachweis darüber, was tatsächlich geprüft wurde, auch wenn der Regelkatalog über künftige Releases wächst.

Limits

  • Request-Body: 4 MB unkomprimiert, 24 MB dekomprimiert (Content-Encoding: gzip wird unterstützt und für große Dokumente empfohlen).
  • Ein Dokument pro Request.
  • Anonyme Rate-Limits: 10 Requests pro Minute und 300 pro Tag je Client, ausgewiesen über die Response-Header RateLimit-Limit, RateLimit-Remaining und RateLimit-Reset, mit Retry-After bei 429-Antworten. Du brauchst mehr? Erstelle einen API-Schlüssel (siehe unten) oder schreib an hello@secani.com.

API-Schlüssel

Höhere, verlässliche Limits gibt es mit einem API-Schlüssel. Schlüssel erstellst du in den Organisationseinstellungen; jeder Schlüssel wird genau einmal angezeigt – direkt beim Erstellen. Gesendet wird er als Authorization: Bearer sk_oscal_…:

curl -sS -X POST https://secani.com/api/oscal/v1/validate \
  -H "authorization: Bearer sk_oscal_..." \
  -H "content-type: application/json" \
  --data-binary @system-security-plan.json

Mit Schlüssel steigen die Limits auf 120 Requests pro Minute und 10.000 pro Tag je Schlüssel – zentral und unabhängig von der einzelnen Server-Instanz durchgesetzt, während die anonymen Limits Best-Effort je Instanz sind. Die anonyme Stufe bleibt bestehen: Requests ohne Authorization-Header verhalten sich unverändert. Ein unbekannter oder widerrufener Schlüssel liefert 401 ERR_INVALID_API_KEY und fällt niemals auf die anonyme Stufe zurück.

Reservierte Parameter

level und rules sind nicht mehr reserviert – sie sind live; siehe Validierungsstufen oben. Es bleibt ein Parameter mit reserviertem Wertebereich:

  • oscal-version – fixiert die Spezifikationsversion und akzeptiert heute nur 1.2.2. Jeder andere Wert ist für künftige OSCAL-Releases reserviert und liefert ERR_UNSUPPORTED_PARAMETER mit einer Erklärung.

OpenAPI

Der kanonische maschinenlesbare Vertrag wird unter /openapi.json ausgeliefert. Die versionierte URL /api/oscal/v1/openapi.json bleibt kompatibel erreichbar. CORS ist offen (*), die API lässt sich also direkt aus browserbasierten Werkzeugen aufrufen.

Siehe auch: der Browser-Validator für die interaktive Nutzung und das TypeScript-Toolkit hinter beiden.