Ogni validatore OSCAL afferma di "convalidare OSCAL". Quasi nessuno di loro sa dirti cosa significa quella frase.
I modelli OSCAL del NIST sono creati in Metaschema: otto moduli root più importazioni condivise, migliaia di righe di XML che definiscono non solo la forma del documento ma la semantica: vocabolari di valori consentiti, regole di unicità, indici di riferimenti incrociati, requisiti di cardinalità. Uno schema JSON cattura la forma. La semantica è il punto in cui i documenti di conformità in realtà vanno storti – e dove “convalidiamo OSCAL” diventa tranquillamente “convalidiamo parte di OSCAL, non siamo sicuri di quale parte”.
Volevamo essere sicuri di quale parte. Quindi abbiamo costruito il nostro validatore nel modo in cui controlleresti un sistema: inizia dalle fonti, enumera tutto e tiene conto di ogni singolo elemento.
La prima decisione è stata quella fondamentale: le fonti NIST sono l’autorità, non l’implementazione di riferimento. Abbiamo fissato usnistgov/OSCAL al commit 21403b4a… (v1.2.2), memorizzato ogni byte Metaschema con hash SHA-256 e trattato la consolidata Java OSCAL CLI per ciò che è realmente: un comparatore da sottoporre a verifica, non una verità da copiare. Incorpora i binding OSCAL 1.2.1: può elaborare documenti 1.2.2, ma non può parlare 1.2.2.
Quindi abbiamo inventariato lessicalmente ogni occorrenza di vincolo nelle fonti bloccate. Tipi non vincolanti: occorrenze, identificate da file e riga, quindi due vincoli che condividono un ID non si riducono mai in uno solo. Il conteggio è arrivato a 348.
Per ogni occorrenza, la nostra build deve contenere esattamente uno dei tre verdetti, applicati da un generatore che ricalcola il registro ad ogni esecuzione:
Non contabilizzati: zero.
Quest’ultimo segmento – le esclusioni – è il punto in cui la cosa si è fatta interessante.
Quando controlli 348 vincoli uno per uno, trovi le cose. Tre delle nostre esclusioni sono difetti nelle fonti NIST stesse:
oscal_mapping-common_metaschema.xml la riga 657 vincola un flag definito cinque righe prima e quindi mai referenziato da nulla. Nessun documento che possa esistere porta questo flag. Il vincolo è insoddisfacente.inventory-item i nomi degli oggetti di scena si applicano solo quando @type È software, hardware, O service - Ma inventory-item dichiara n type bandiera affatto. (Il suo vicino, asset-id, è esso stesso commentato nel sorgente.) Il predicato non può mai corrispondere.with-child-controls. Un essere umano che legge la fonte li vede; lo schema compilato non li applica mai. Tutti e tre i risultati sono riportati a monte: usnistgov/OSCAL#2254, #2255, #2256.E l'audit ha operato in entrambe le direzioni: il nostro valutatore aveva un bug in cui i vincoli mirati ai flag (come i valori consentiti di action/@type) compilato nell'inventario ma silenziosamente mai sparato. Non l'abbiamo trovato per fortuna: il cancello di chiusura ha rifiutato di accettare prove per questi due eventi, che è proprio la modalità di fallimento che l'intero sistema è progettato per denunciare.
Affermare che "l'implementazione di riferimento manca di cose" dalla sola ispezione della fonte è esattamente il tipo di affermazione non dimostrata che questo progetto esiste per uccidere. Quindi abbiamo scaricato Java OSCAL CLI 3.2.0 da Maven Central, l'abbiamo verificato con l'hash ed abbiamo eseguito entrambi i validatori su una famiglia di dispositivi i cui documenti di base passano in modo pulito su entrambi i lati, quindi ogni disaccordo è attribuibile a una modifica inserita.
OSCAL 1.2.2 ha modificato esattamente due vincoli oltre i bump di versione (entrambi nel modello SSP). La CLI Java, che incorpora i collegamenti 1.2.1, si trova dalla parte sbagliata rispetto a ogni conseguenza osservabile:
rel="validation" il collegamento del componente viola 1.2.2. Java: valido, uscita 0.rel="validated-by" il collegamento va bene per 1.2.2 (il vincolo è stato eliminato). Java: non valido.responsible-role senza opzionale party-uuid va bene per 1.2.2 – Il NIST ha aggiunto il predicato appositamente per risolvere questo problema. Errori Java con, letteralmente, Key reference [null] not found.Poi uno che non riguarda affatto l'inclinazione della versione: un catalogo i cui metadati action dichiara "type": "invented-type" – vietato alla riga 877 del metadati Metaschema sia nei sorgenti 1.2.2 che in quelli 1.2.1 Java incorporati. Java lo dichiara valido, in JSON e XML. Il vincolo prende di mira un flag; i vincoli mirati a flag che silenziosamente non si attivano è precisamente la classe di bug che il nostro cancello di completezza ha catturato nel nostro valutatore. L'implementazione di riferimento ha la stessa classe di bug e nessuna porta di chiusura per rilevarlo. Lo abbiamo segnalato a monte come metaschema-framework/oscal-cli#279. (Abbiamo mappato la classe meccanicamente: esattamente 2 su 200 occorrenze di valori consentiti prendono di mira i flag e l'unico membro con grado di errore è quello che abbiamo testato in tempo reale. Nessun resto non testato.)
E l'onestà vince, perché la corsa è andata in entrambe le direzioni: il nostro validatore ha rifiutato il catalogo SP 800-53 rev5 del NIST. Venti errori, tutti un difetto: il nostro valutatore dell'indice ha trattato un campo chiave opzionale mancante come una violazione laddove le specifiche Metaschema indicano che è una chiave nulla. Java ha accettato il file; ci sbagliavamo; l'abbiamo risolto lo stesso giorno e 800-53 convalida pulito. La corsa in seguito ne ha catturato un secondo: abbiamo continuato a applicare il vocabolario di tipo azione OSCAL anche quando action/@system dichiarato un URI personalizzato: l'esatta segmentazione per organizzazione richiesta dalle osservazioni del NIST. Anche risolto. Un cablaggio differenziale che trova sempre e solo i difetti dell'altra parte non è un cablaggio, è marketing.
(Anche archiviato sotto "entrambi i lati": nessuno dei due risolutori ha convalidato semanticamente il proprio output. Quello di Giava resolve-profile scriverà felicemente un catalogo proprio di Java validate poi rifiuta - e il nostro ha fatto lo stesso, con vincoli di schema ma non di semantica. La nostra ora si rifiuta di scrivere risoluzioni semanticamente non valide; Java ancora non può, perché chiudere quel buco richiede un livello semantico di cui ti fidi.)
La seconda cosa che manca agli strumenti esistenti: i documenti OSCAL non vivono soli. Un risultato di valutazione importa un piano di valutazione, che importa un SSP, che importa un profilo, che si risolve rispetto ai cataloghi. La documentazione del modello è piena di relazioni che nessun validatore di file singolo può verificare: "l'obiettivo di questo risultato deve risolversi in un'istruzione nella linea di base", "questo POA&M deve identificare il suo sistema".
Quindi abbiamo creato una convalida incrociata di documenti che risolva questi limiti in modo reale. Chiedigli di controllare un SSP e risolverà la linea di base importata attraverso la pipeline completa di risoluzione del profilo (bozza-spec) fino ai cataloghi, calcola il set di controlli selezionato e ti dice:
{
"ruleId": "SSP-003.b",
"severity": "warning",
"path": "/…/implemented-requirements/1/control-id",
"message": "implemented control 'ac-99' is not supplied by the resolved import-profile 'file:///…/baseline.json'"
}
Con una regola di progettazione cruciale: questi controlli delle relazioni sono interpretazioni di prosa documentata, e noi li trattiamo in questo modo: disattivati per impostazione predefinita, avvisi non errori, l'ambito di risoluzione di ciascun campo è fissato alla riga di origine e qualsiasi cosa meramente desumibile esclusa per nome. Laddove le coperture standard, un validatore non dovrebbe bluffare. (Il nostro esempio preferito: le specifiche POA&M dicono che è richiesta un'importazione SSP o un ID di sistema: "Potrebbero essere presenti entrambi". Quindi avvisiamo solo quando nessuno esiste. Nessuna esclusiva inventata-or.)
Perché i documenti risiedono in browser, funzioni serverless, CLI e database e volevamo un validatore in tutti questi, non un sidecar JVM accanto a ciascuno. I validatori sono moduli Ajv autonomi precompilati: JavaScript generato in modo semplice, compilazione di schemi runtime zero, output stabile in byte. Lo stesso codice che alimenta le nostre superfici di convalida viene eseguito invariato nella scheda del tuo browser e nella nostra CLI. E il determinismo non è solo una questione operativa: è ciò che rende possibili le prove hash-appuntate.
import { createDiagnosticsOscalProcessor } from "@secani/oscal/diagnostics";
const result = createDiagnosticsOscalProcessor({ maxIssues: 50 }).validate(doc);
validate --resolve-imports --interpretive all)La relazione tecnica completa – modello di autorità, chiusura di completezza, tabella delle entrate differenziali e ciò che deliberatamente non rivendichiamo – vive nella documentazione del validatore. Il validatore è in fase di stage privata prima di un rilascio open source; IL API di convalida ospitata espone il livello dello schema oggi, con il livello semantico a seguire.
Secani collega gli ambiti, le prove, i compiti e gli agenti AI in uno spazio di lavoro condiviso.
OLIR fornisce contenuto e governance della mappatura. OSCAL fornisce la struttura leggibile dalla macchina per utilizzare tali mappature nell'analisi delle lacune, nel riutilizzo delle prove e nei flussi di lavoro con impatto sul cambiamento.
OSCAL trasforma i documenti di compliance in dati strutturati: otto modelli di documenti, tre formati e un ecosistema che sta diventando lo standard per la regolamentazione.
Con RFC-0024 e le Regole Consolidate 2026, FedRAMP rende obbligatori i dati di autorizzazione strutturati. Le scadenze sono scaglionate – la direzione è inequivocabile.