← All packages / @reso-standards/reso-certification / `reso-cert` – CLI reference

`reso-cert` – CLI reference

reso-cert – CLI reference

The unified command-line entry point for RESO certification compliance testing. This is the complete command reference; for a quick start and the SDK API see the package README.

# from a built checkout
node reso-certification/dist/cli/index.js <command> [options]
# or, when installed
reso-cert <command> [options]

Every command sets a process exit code: 0 = pass / valid, 1 = one or more failures, 2 = runtime or IO error. Machine-readable output goes to stdout; the human-readable summary goes to stderr, so you can pipe --output json cleanly.

There is no --version option on any subcommand. --version belongs to reso-cert itself and prints the package version, so a subcommand could never receive it: passing it printed the version and exited 0 without running the command. Data Dictionary versions are --dd-version, the Web API Core and Add/Edit spec versions are --spec-version.

Environment (.env)

Several commands take their service URL and credentials from the environment rather than from flags, so a working .env is often the difference between a command running and a command refusing.

Where it is found. At startup the CLI looks for a file literally named .env in three places, in order, and the first one found wins – the rest are not read:

  1. the current working directory
  2. the reso-certification package root
  3. the reso-tools monorepo root

A variable already set in the real environment is never overwritten by the file, so RESO_SERVICES_URL=… npx reso-cert … overrides whatever .env says.

Which environment a run touches is decided by TOKEN_URI, and by nothing else. RESO_SERVICES_URL is the same value for every environment, so reading it tells you nothing about which one you are pointed at. The environment is fixed when the token is minted: authenticating against the QA certification host produces a token carrying qa, the production host produces one carrying production, and every later call reads that off the token. If you want to know which environment a command will write to, look at the host in TOKEN_URI.

The variables

Variable Used by What it is
RESO_SERVICES_URL find-variations, rcf, update-variations, the variations-review commands Base URL of the Variations Service. Same for every environment.
TOKEN_URI the same commands OAuth2 token endpoint. This is what selects QA versus production.
CLIENT_ID, CLIENT_SECRET the same commands OAuth2 client credentials the token is minted from.
FT_ADMIN_SECRET update-variations --fast-track Fast Track admin credential. A fast-track submission is refused without it, before any request is made.
CERT_AUTH_API_BASE_URL, CERT_AUTH_API_USERNAME, CERTIFICATION_API_KEY, CURRENT_PROVIDER_UOI the SDK’s provider-token fallback The second auth path, used when the OAuth2 variables are absent.

Two auth paths, in that order. A command first tries an OAuth2 client-credentials token from TOKEN_URI / CLIENT_ID / CLIENT_SECRET. If those are not configured it falls back to minting a provider token from the CERT_AUTH_API_* set. A command that reports “requires authentication” is telling you neither set is complete, not that one of them was rejected – a rejected credential reports separately.

Nothing here is passed on the command line, and there is no flag that overrides the service URL. Commands that talk to a live OData server take their own --url, --auth-token and --client-id/--client-secret/--token-url; those are for the provider’s endpoint and are a different thing from the RESO service credentials above.

Commands at a glance

Command What it does
add-edit RCP-010 Add/Edit endorsement compliance
entity-event RCP-027 EntityEvent change-tracking compliance
core Web API Core 2.1.0 compliance
dd Data Dictionary 2.1 compliance (replicate + validate a live endpoint)
metadata Validate OData CSDL/EDMX and convert it to a metadata report
schema validate / schema generate JSON-Schema tools for a metadata report
replicate Pull data from an endpoint using an OData replication strategy
find-variations DD variations review via the v2 Variations Service
rcf RESO Common Format: infer a metadata report from payload data and run variations
metadata-report adapt Back-fill the resources[] block on a DD 2.0/2.1 report
update-variations Submit reviewed variation suggestions (admin)
submit-variations-report Send a DD run’s variations report to start or refresh a review
submit-variation-decisions Mark a report from a sheet of actions and comments, and submit it
list-variation-reviews The variations in review – yours as a provider, the whole pool as an admin (read-only)
variations-review-status Where each variations submission stands (read-only)

The first four are endorsement runners (a full compliance pipeline against a live server). The rest are per-step utilities – each does one stage of a run in isolation, so you can script the pipeline, debug a single step, or feed its artifact into the next.

Shared options

Auth (endorsement runners, replicate, and find-variations --from-server):

Option Meaning
--auth-token <token> Pre-fetched bearer token
--client-id <id> --client-secret <secret> --token-url <url> OAuth2 client-credentials – minted at run time

Output (endorsement runners):

Option Meaning
--verbose Detailed line-by-line output
--output <console\|json> Output format (default console)
--output-dir <path> Directory for compliance reports

Per-step utilities take --output-dir too, and accept - to mean stdin (for inputs) or stdout (for --output-dir -), so they compose in a pipe.

Endorsement runners

add-edit

RCP-010 Add/Edit endorsement testing.

reso-cert add-edit --url https://api.example.com --auth-token TOKEN
reso-cert add-edit --mock                       # against a bundled mock OData server
reso-cert add-edit --config ./configs/add-edit-config.json   # multi-provider batch
Option Default Meaning
--url <url> – Server base URL (mutually exclusive with --config)
--config <path> – Config file with one or more provider entries
--resource <name> Property OData resource under test
--payloads <dir> – Directory of payload JSON files
--metadata <path> – Local XML metadata (for --mock)
--mock – Start a bundled mock OData server
--spec-version <v> 2.0.0 Spec version stamped into the report

Provide one of --url, --config, or --mock.

entity-event

RCP-027 EntityEvent change-tracking testing.

reso-cert entity-event --url https://api.example.com --auth-token TOKEN --mode observe

Adds, beyond the shared options: --mode <observe|full> (default observe; full performs canary writes), --writable-resource <name> (default Property), --payloads-dir <dir>, --max-events <n> (default 1000), --batch-size <n> (100), --poll-interval <ms> (5000), --poll-timeout <ms> (30000), --metadata <path>, --mock. Provide one of --url, --config, or --mock.

core

Web API Core 2.1.0 compliance. Core 2.0.0 remains certifiable and is selectable per run.

reso-cert core --url https://api.example.com --auth-token TOKEN --spec-version 2.1.0
Option Default Meaning
--url <url> – Server base URL (mutually exclusive with --config)
--config <path> – Config file with one or more provider entries
--resources <list> well-known list Comma-separated resource names
--spec-version <2.0.0\|2.1.0> 2.1.0 Spec version. Config-file mode takes the version from the config entry and ignores this flag.
--enum-mode <auto\|string\|collections\|isflags> auto How enumerations are represented (auto-detected by default)
--field-overrides <list> (auto) Comma-separated Resource.Field (a bare Field is not accepted). The named field replaces automatic selection for its data type on that resource, and for an enumeration for its own representation: it is the field tested, nothing automatic sits behind it, and a field the service will not filter on fails its test. Name two fields of the same type and both are tried, in the order written. A sparse override: every slot not named here is still auto-selected. An entry that resolves to nothing leaves its slot automatic and is reported as unmatched. Replaces coreOptions.fieldOverrides from a config rather than merging with it.
--prefer-fields <list> – Removed in 0.11.1. Prints an explanation and is ignored. Use --field-overrides; note that the behavior changed from re-ordering candidates to replacing them, so a named field now owns its outcome.
--full-coverage – Fail if any data-type category has no coverage across all resources
--originating-system-name <v> – Scope resource queries to OriginatingSystemName eq <v> (multi-tenant providers)
--originating-system-id <v> – Scope by OriginatingSystemID instead. Used only when no name is given
--save-payloads <dir> (off) Write every request and response to <dir>. See below.

Provide one of --url or --config.

--save-payloads records what the server actually returned, which the compliance report does not: the report keeps each scenario’s requestUrl and no body, and a response body is retained only as error detail. A run that passes therefore leaves nothing to inspect. That is enough to audit a skip, since a skipped scenario issues no request at all, and not enough to audit a pass: whether an assertion read what it meant to read cannot be checked after the fact.

Two files per request, sharing a stem so they sort together:

0002-get-Property-top-1000.json        the response body, byte for byte as it arrived
0002-get-Property-top-1000.meta.json   method, url, status, headers, body size

The body is written exactly as it came off the wire rather than re-serialized from the parsed object, so key order and Edm.Decimal precision are preserved and the file is what the server sent. $metadata is saved as .xml, following the response’s own content type.

Headers are kept by allowlist and everything else is dropped, so no credential is written: the bearer token is never carried over, and a header reaches a file only by being named in KEPT_HEADERS. The list is the OData protocol family, Accept / Content-Type, Accept-Language / Content-Language, Prefer / Preference-Applied, Retry-After and WWW-Authenticate – each one a header the RESO specs or the protocol turn on. WWW-Authenticate is a server challenge and is kept deliberately: it is what names the expected scheme on a 401.

Off unless the flag is given. A capture is a copy of a provider’s data on disk, and it is large – one resource against a reference server produced 23 MB from a single page request. Point it outside the repository; .gitignore catches the conventional directory names and not an arbitrary path.

dd

Data Dictionary 2.1 compliance – replicates a live endpoint and validates it against the DD. DD 2.0 remains certifiable and is selectable per run.

reso-cert dd --url https://api.example.com --auth-token TOKEN
reso-cert dd --url https://api.example.com --auth-token TOKEN --dd-version 2.0
reso-cert dd --config ./sample-configs/dd-config.json        # multi-provider batch
Option Default Meaning
--url <url> – Server base URL (mutually exclusive with --config)
--config <path> – Config file with one or more provider entries
--dd-version <v> 2.1 DD version. 2.0 and 2.1 are certifiable. Anything else is refused, 1.7 included. In config-file mode the entry’s version stands unless this flag is given
--limit <n> 100000 Max records replicated per resource
--strict on Fail the run on JSON-schema validation errors. On by default, so this flag is only needed to be explicit. Variations fail a run independently of this setting
--no-strict – Record schema-validation errors without failing on them, so a long run surveys everything to fix. Validation still runs. The run is not eligible for certification and says so in its verdict
--skip-variations – Do not check variations. The run is not eligible for certification
--batch-expand – Batch every expansion per resource into one $expand request
--originating-system-name <v> – Append OriginatingSystemName eq <v> to every replication query (multi-tenant providers)
--originating-system-id <v> – Append OriginatingSystemID instead. Used only when no name is given

Provide one of --url or --config.

The variations step computes through the Variations Service. It authenticates with the OAuth2 client-credentials token minted from .env (TOKEN_URI / CLIENT_ID / CLIENT_SECRET), the same way find-variations does, so a run computes against the environment those credentials belong to; with them absent it falls back to the CERT_AUTH_API_* provider-token mint. In --config mode every entry’s report lands as variations-report.json under the output dir.

--skip-variations exists for environments with no Variations Service to reach, such as a continuous-integration run against the reference server. It reports the step as skipped rather than omitting it, and because the Data Dictionary requires every step to have passed, the run is recorded as not eligible for certification: report-detailed.json carries a certification object naming the step, and the run summary prints a Not eligible for certification line. The run’s outcome is unaffected – it still describes what happened while the run executed. An absent RESO_SERVICES_URL is never treated as a skip; that still fails the run, so a misconfigured machine cannot quietly stop checking variations.

Per-step utilities

metadata

Validate OData CSDL/EDMX (XSD + semantic) and convert it to a RESO-format metadata report. This is the first cert step and the one that gates the rest – if the metadata is invalid nothing downstream is meaningful.

reso-cert metadata -m metadata.xml --dd-version 2.0 --output-dir ./out
cat metadata.xml | reso-cert metadata -m - --no-report       # validate only, from stdin

-m, --metadata <path> (required; - for stdin) · --dd-version <ddVersion> (default 2.1, stamped into the report) · --odata-version <4.0|4.01> (auto-detected when omitted) · --output-dir <path> (default .; - for stdout) · --no-report (validate only). Exit 0 valid / 1 invalid / 2 IO.

schema

JSON-Schema tools for a metadata report.

reso-cert schema generate -m metadata-report.json --output-dir ./out
reso-cert schema validate -m metadata-report.json -p payload.json --output-dir -
  • schema generate – build a JSON Schema from a metadata report. -m, --metadata (required; - stdin) · -a, --additional-properties · --output-dir (- stdout).
  • schema validate – validate a payload against a report’s schema. -m, --metadata (required) · -p, --payload (required; an OData collection { value: [...] } or a single record; - stdin) · --dd-version (default 2.1) · -r, --resource (else inferred from the payload @odata.context) · -s, --settings <schema-validation-settings.json> · -a, --additional-properties (default: reject unknown fields) · --output-dir. Exit 0 pass / 1 schema errors / 2 IO.

replicate

Pull data from a resource (or every resource in a metadata report) using an OData replication strategy. Writes a data-availability report under --output-dir.

reso-cert replicate -u https://api.example.com -s TimestampDesc -r Property -l 1000 \
  --auth-token TOKEN --output-dir ./out
Option Meaning
-u, --url <uri> (required) OData service-root URI
-s, --strategy <s> (required) TopAndSkip | TimestampAsc | TimestampDesc | NextLink
-r, --resource <name> Single-resource mode
-m, --metadata <path> Report-driven mode – replicate every resource in the report
-x, --expansions <list> Comma-separated expansions (single-resource mode)
-f, --filter <expr> OData $filter
-t, --top <n> / --max-page-size <n> Page size / odata.maxpagesize (NextLink)
--orderby <expr> OData $orderby
-l, --limit <n> Stop after N total records
--dd-version <ddVersion> DD version (default 2.1)
--save-results Also write every raw response page to disk
--json-schema-validation Validate each payload against the metadata schema (requires --metadata)
--strict / --no-strict Fail on validation errors, or record them without failing. Strict is the default, and is inert unless validation is on
--originating-system-name <v> / --originating-system-id <v> Append an OriginatingSystem* filter to every query

Auth is via the shared --auth-token / OAuth2 flags.

find-variations

DD variations review for a metadata report, computed through the v2 Variations Service (/compute). Emits data-dictionary-variations.json.

reso-cert find-variations -m metadata-report.json --output-dir ./out
reso-cert find-variations --from-server -u https://api.example.com --auth-token TOKEN

Exactly one metadata source: -m, --metadata <file> (- stdin) or --from-server with -u, --url <url> (fetches and serializes the endpoint’s $metadata in memory). -f, --fuzziness <0–1> · --dd-version (default 2.1) · --output-dir (- stdout). Two auth contexts: the auth flags authenticate the --from-server fetch; the /compute call authenticates to the Variations Service with .env service credentials.

rcf

RESO Common Format certification. An RCF provider delivers data rather than a schema, so there is no $metadata to read: rcf infers the metadata report and the data-availability report from the payloads, then runs variations against the inferred report. DD schema validation is opt-in, under --schema-validate.

reso-cert rcf -i ./rcf-export/ --output-dir ./out
reso-cert rcf -i payloads.zip --schema-validate --output-dir ./out
reso-cert rcf -i payload.json --skip-variations --output-dir ./out   # offline, no credentials

-i, --input <path> (required; a .json file, a .zip or a directory of payloads or records) · --dd-version <v> · -f, --fuzziness <0–1> (default 0.25) · --schema-validate · --strict (fail on the first schema error, with --schema-validate) · --skip-variations · -a, --additional-properties (accepted and inert: RCF is always extensible) · --output-dir <path> (default .).

Writes metadata-report.json and data-availability-report.json, plus data-dictionary-variations.json when the variations step runs. The run version is --dd-version when given, else the version in the payload’s @reso.context, else DD 2.0. The variations call authenticates with the .env service credentials, as find-variations does. --skip-variations mints no token, so an inference-only run needs none.

Exit 0 pass / 1 schema errors / 2 nothing certifiable ingested or a variations pass that degraded. A file whose @reso.context cannot be read is a schema error under --schema-validate and a 2 without it, so an unreadable submission never reads as a clean pass. A variations outage leaves both reports on disk and names the reason. An auth misconfiguration is the exception: the run cannot do what was asked, so it fails with nothing written.

metadata-report adapt

Synthesize the top-level resources[] block on a DD 2.0/2.1 metadata report so it can be loaded by tools that expect a DD 2.2-shaped report (notably the Reference Server). Idempotent – DD 2.2+ reports pass through unchanged.

reso-cert metadata-report adapt --in report-2.0.json --out report-adapted.json --pretty

--in <path> (required) · --out <path> (required) · --pretty.

Admin

update-variations

Submit human-reviewed variation suggestions from a CSV to the cloud Variations Service. Auth is an OAuth2 client-credentials token minted from .env.

reso-cert update-variations -s suggestions.csv --admin-review

-s, --suggestions <path> (required CSV) · --admin-review xor --fast-track (how the submission is flagged) · --overwrite (allow overwriting canonical entries) · --chunk-size <n> (suggestions per request, default 1000). The run summary reports submitted, per-status stats, and any permission-denied / validation-failed / corrections – review those before assuming a clean run.

Sheet columns. Headers are matched case-insensitively and trimmed; anything unrecognized is reported as skipped rather than dropped silently.

Column  
Resource Name required on every row
Field Name, Lookup Value what the row is about
Suggested Resource Name, Suggested Field Name, Suggested Lookup Value the target
Suggested Standard Lookup Value, Suggested Legacy OData Value a lookup target, by display name or legacy value
Suggested Related Resource Name, Suggested Related Field Name, Suggested Related Lookup Value an expansion target
Strategy how the mapping was arrived at: Substring, Edit Distance, Fast Track, Admin Review
Outcome  

A row must name a target with any one of the suggested columns, or carry an Outcome. A row that does neither is refused by name, for example row 3 (Property.OpenHouse), because it would ask for nothing. Strategy alone will not carry a row; it says where a mapping came from, not what the mapping is.

This is the same shape list-variation-reviews --csv writes, so a review exports, gets edited and goes back in without reshaping the file.

submit-variations-report

Send the variations-report.json a DD run produced to the Variations Service, which starts a review or refreshes one. The whole report goes up, buckets and all, and the service builds the pool rows from it – so each row keeps the matcher’s suggestions, the strategy that produced its mapping, and the element level.

reso-cert submit-variations-report --report out/.../variations-report.json
reso-cert submit-variations-report --report <path> --dry-run     # contacts nothing
reso-cert submit-variations-report --report <path> --overwrite   # proceed over an existing pending review

-r, --report <path> (required) · --overwrite · --dry-run · --json.

A fresh submission is a full replace of that report’s review rows, declared explicitly rather than inferred, so an omission is read as a delta and never as a destructive operation. --overwrite proceeds over an existing pending review; it never proceeds over a lock, which means somebody is reviewing right now. A dry run contacts nothing and so needs no credentials.

submit-variation-decisions

Apply a sheet of actions and comments to a variations report, then submit it. This is the review loop for anyone without the desktop client: export, edit, submit.

reso-cert list-variation-reviews --status pending --csv > review.csv
# fill in Action on the rows you decided
reso-cert submit-variation-decisions --report variations-report.json --decisions review.csv

The sheet’s Action column takes ignore, remove or submit-to-ft. A row names an element and the sheet says what to do with it; the report’s own suggestions carry their provenance, so nothing about the mapping needs restating.

Deciding on a subset is normal. Rows with no Action and no Comment are left as they are and reported by name, so a row you left blank on purpose and a row whose Action you mistyped are both visible rather than one of them passing as a no-op. A sheet where no row asks for anything is refused, because nothing would be submitted.

One push carries the whole sheet. If any row is unusable the report is returned unchanged rather than half-applied, so you never have to work out which rows landed.

Variations review (read-only)

Both read the same routes the web client’s review page uses, with the same auth as update-variations (an OAuth2 client-credentials token from .env, falling back to the CERT_AUTH_API_* provider-token mint). Neither writes anything.

list-variation-reviews

The items in the review pool: a provider token sees its own rows, an admin token the org-wide pool. One line per variation key, collapsed across every tuple that flagged it.

reso-cert list-variation-reviews --status pending
reso-cert list-variation-reviews --status pending --provenance   # every submitting tuple under each item
reso-cert list-variation-reviews --element-type lookup --json    # exactly what the service returned
reso-cert list-variation-reviews --status pending --csv > review.csv   # a sheet to edit and submit back

--status <pending|ft-submitted|resolved> · --element-type <resource|field|lookup> · --provenance (one line per submitting tuple: when, which provider/USI/recipient, by whom, environment, role) · --page-size <n> (items per request; every page is fetched regardless) · --json · --csv. The summary table shows the mapping, the strategy where the pool holds one, the tuple count and the earliest submission.

--csv writes the sheet the desktop client exports, plus Strategy, Status and empty Action and Comment columns. That makes it a template rather than a report: fill in Action and feed the same file to submit-variation-decisions without reshaping it. Rows go to stdout and the item count to stderr, so > review.csv yields a clean file.

reso-cert list-variation-reviews --status pending --csv > review.csv
# fill in Action on the rows you decided; leave the rest blank
reso-cert submit-variation-decisions --report variations-report.json --decisions review.csv

A row the pool holds with no suggested mapping at all cannot be read back: the sheet is all-or-nothing, and such a row would ask for nothing. The error names the element, for example row 3 (Property.OpenHouse). Those rows are unreviewable in the pool too, so the fix is to resolve or remove them rather than to edit the sheet.

variations-review-status

Your submissions with their lifecycle and review status, one line each.

reso-cert variations-review-status
reso-cert variations-review-status --review-status in-review   # admin: every provider's, by review status

--review-status <none|in-review|resolved> (admin queue instead of your own) · --json.

Config-file mode

add-edit, entity-event, core and dd accept --config <path> instead of --url to run a batch of providers from one file (each entry carries its own server URL, UOIs, and optional per-entry overrides). See the sample configs under sample-configs/.