Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions contents/sep-contract-verification-registry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Contract Verification Registry API — schemas and examples

Supporting files for the Contract Verification Registry API SEP
(`ecosystem/sep-contract-verification-registry.md`). They let implementers
validate responses against a machine-readable schema and use the documented
examples as test fixtures.

## Layout

- `status-object-1.0.schema.json` — JSON Schema (draft 2020-12) for the body of a
`200 OK` or `202 Accepted` response from `GET /wasms/:wasm_hash.json`.
- `error-1.0.schema.json` — JSON Schema for the body a `400 Bad Request` MAY carry.
Other non-2xx statuses are signaled by status code and define no body.
- `examples/status/` — example status objects, named by HTTP status and
scenario. Each validates against `status-object-1.0.schema.json`.
- `examples/error/` — example `400` error bodies, named `<error-code>.json`.
Each validates against `error-1.0.schema.json`.

The example files are the exact JSON snippets embedded in the SEP, extracted so
they can be validated (e.g. in CI).

## Validating

Any draft 2020-12 validator works. The schemas declare their draft via
`$schema`, so a validator that respects it needs no extra flags.

Using
[`check-jsonschema`](https://github.com/python-jsonschema/check-jsonschema)
(`pipx install check-jsonschema`):

```
# Status objects
check-jsonschema --schemafile status-object-1.0.schema.json examples/status/*.json

# Error bodies
check-jsonschema --schemafile error-1.0.schema.json examples/error/*.json
```
26 changes: 26 additions & 0 deletions contents/sep-contract-verification-registry/error-1.0.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/stellar/stellar-protocol/blob/master/contents/sep-contract-verification-registry/error-1.0.schema.json",
Comment thread
fnando marked this conversation as resolved.
"title": "Contract Verification Error",
"description": "The body a 400 Bad Request MAY carry to disambiguate why the request was rejected. Other non-2xx statuses are signaled by status code and define no body.",
"type": "object",
"required": ["schema_version", "error", "message"],
"additionalProperties": false,
"properties": {
"schema_version": {
"type": "string",
"description": "The version of the response schema, as MAJOR.MINOR, versioned independently of the SEP. MAJOR increments on a breaking change; MINOR on an additive change. This schema describes version 1.0.",
"const": "1.0"
},
"error": {
"type": "string",
"description": "A stable, machine-readable error code. Clients SHOULD branch on this rather than message, and MUST tolerate codes they do not recognize.",
"enum": ["400_invalid_wasm_hash", "400_other"]
},
"message": {
"type": "string",
"description": "A human-readable description of the error. Wording is not stable and is intended for display and debugging.",
"minLength": 1
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"schema_version": "1.0",
"error": "400_invalid_wasm_hash",
"message": "wasm_hash is not a valid lowercase hex SHA-256."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"schema_version": "1.0",
"error": "400_other",
"message": "The request could not be processed."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"schema_version": "1.0",
"wasm_hash": "cb2fc3a1b4d5e6f7081928374655647382910abcdef0123456789abcdef01234",
"updated_at": "2026-06-04T12:00:00Z",
"source_code_verifications": [
{
"verifier": { "name": "Example Verification Service" },
"status": "verified",
"out_of_band": true,
"processed_at": "2026-06-04T12:00:00Z"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"schema_version": "1.0",
"wasm_hash": "cb2fc3a1b4d5e6f7081928374655647382910abcdef0123456789abcdef01234",
"updated_at": "2026-06-04T13:00:00Z",
"source_code_verifications": [
{
"verifier": { "name": "Verifier A", "url": "https://a.example.com" },
"status": "verified",
"source_repo": "https://github.com/user/my-contract",
"source_rev": "abc1234567890abcdef1234567890abcdef12345",
"processed_at": "2026-06-04T12:00:00Z"
},
{
"verifier": { "name": "Verifier B", "url": "https://b.example.com" },
"status": "mismatched",
"source_repo": "https://github.com/user/my-contract",
"source_rev": "abc1234567890abcdef1234567890abcdef12345",
"rebuilt_hash": "999888777666555444333222111000fedcba9876543210fedcba9876543210fe",
"processed_at": "2026-06-04T13:00:00Z"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schema_version": "1.0",
"wasm_hash": "cb2fc3a1b4d5e6f7081928374655647382910abcdef0123456789abcdef01234",
"updated_at": "2026-06-04T12:00:00Z",
"source_code_verifications": [
{
"verifier": { "name": "Example Verification Service" },
"status": "unverified"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"schema_version": "1.0",
"wasm_hash": "cb2fc3a1b4d5e6f7081928374655647382910abcdef0123456789abcdef01234",
"updated_at": "2026-06-04T12:05:00Z",
"source_code_verifications": [
{
"verifier": {
"name": "Example Verification Service",
"url": "https://verify.example.com",
"logo_url": {
"light": "https://verify.example.com/logo.png",
"dark": "https://verify.example.com/logo-dark.png"
}
},
"status": "verified",
"bldimg": "docker.io/stellar/stellar-cli@sha256:1f2e3d4c5b6a79887766554433221100ffeeddccbbaa99887766554433221100",
"bldopt": ["--manifest-path=contracts/foo/Cargo.toml", "--optimize"],
"source_repo": "https://github.com/user/my-contract",
"source_rev": "abc1234567890abcdef1234567890abcdef12345",
"processed_at": "2026-06-04T12:00:00Z",
"results_urls": [
"ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
"ar://AbCdEf0123456789AbCdEf0123456789AbCdEf0123456789ABC"
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"schema_version": "1.0",
"wasm_hash": "cb2fc3a1b4d5e6f7081928374655647382910abcdef0123456789abcdef01234",
"updated_at": "2026-06-04T12:00:00Z",
"source_code_verifications": [
{
"verifier": { "name": "Example Verification Service" },
"status": "unverified"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/stellar/stellar-protocol/blob/master/contents/sep-contract-verification-registry/status-object-1.0.schema.json",
Comment thread
fnando marked this conversation as resolved.
"title": "Contract Verification Status Object",
"description": "The body returned by GET /wasms/:wasm_hash.json on a 200 OK or 202 Accepted response.",
"type": "object",
"required": [
"schema_version",
"wasm_hash",
"updated_at",
"source_code_verifications"
],
"additionalProperties": false,
"properties": {
"schema_version": {
"type": "string",
"description": "The version of the response schema, as MAJOR.MINOR, versioned independently of the SEP. MAJOR increments on a breaking change; MINOR on an additive change. This schema describes version 1.0.",
"const": "1.0"
},
"wasm_hash": {
"type": "string",
"description": "The queried wasm hash, echoed back. Lowercase hex SHA-256.",
"pattern": "^[0-9a-f]{64}$"
},
"updated_at": {
"type": "string",
"description": "RFC 3339 UTC timestamp of when this record was last updated across all of its verifications. Always present.",
"format": "date-time"
},
"source_code_verifications": {
"type": "array",
"description": "One or more rebuild-from-source verification results, each from one verifier.",
"minItems": 1,
"items": {
"type": "object",
"required": ["verifier", "status"],
"additionalProperties": false,
"properties": {
"verifier": {
"type": "object",
"description": "Identity of the verifier that produced (or is producing) this result.",
"required": ["name"],
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"description": "A human-readable name for the verifier.",
"minLength": 1
},
"url": {
"type": "string",
"format": "uri",
"description": "A URL identifying the verifier or describing its methodology."
},
"logo_url": {
"description": "A logo for the verifier. Either a URL string, or an object with light and/or dark URL variants for light and dark backgrounds. The image SHOULD be square; a transparent background is recommended.",
"oneOf": [
{ "type": "string", "format": "uri" },
{
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"properties": {
"light": { "type": "string", "format": "uri" },
"dark": { "type": "string", "format": "uri" }
}
}
]
}
}
},
"status": {
"type": "string",
"description": "The verification status value.",
"enum": ["verified", "mismatched", "unverified"]
},
"out_of_band": {
"type": "boolean",
"description": "When true, this verification was established outside SEP-58's reproducible-build mechanisms (e.g. a custom or non-allowlisted build image, or private source). Absent or false means a standard reproducible SEP-58 verification."
},
"bldimg": {
"type": "string",
"description": "SEP-58 bldimg. Fully-qualified container image pinned by digest.",
"pattern": "^(?:localhost(?::\\d+)?|[^\\s@/]*[.:][^\\s@/]*)/[^\\s@]+@sha256:[0-9a-f]{64}$"
},
"bldopt": {
"type": "array",
"description": "SEP-58 bldopt. One entry per build flag; order is not significant.",
"items": {
"type": "string",
"pattern": "^--[A-Za-z][A-Za-z0-9_-]*(=.+)?$"
}
},
"source_repo": {
"type": "string",
"description": "SEP-58 source_repo.",
"pattern": "^(https?://\\S+|github:[^/\\s]+/[^/\\s]+)$"
},
"source_rev": {
"type": "string",
"description": "SEP-58 source_rev. Full 40-char SHA-1 of the source commit.",
"pattern": "^[0-9a-f]{40}$"
},
"tarball_url": {
"type": "string",
"description": "SEP-58 tarball_url.",
"pattern": "^https?://\\S+$"
},
"tarball_sha256": {
"type": "string",
"description": "SEP-58 tarball_sha256. Lowercase hex SHA-256 of the source tarball.",
"pattern": "^[0-9a-f]{64}$"
},
"rebuilt_hash": {
"type": "string",
"description": "The conflicting lowercase hex SHA-256 the verifier produced by rebuilding from source. Present only when status is mismatched; omitted for verified (where it would equal wasm_hash) and unverified.",
"pattern": "^[0-9a-f]{64}$"
},
"processed_at": {
"type": "string",
"description": "RFC 3339 UTC timestamp of when this verification was processed. Required for verified and mismatched; must be omitted for unverified.",
"format": "date-time"
},
"results_urls": {
"type": "array",
"description": "Zero or more open-scheme URIs to an externally-published record of this verification.",
"items": {
"type": "string",
"format": "uri"
}
}
},
"allOf": [
{
"$comment": "rebuilt_hash is the conflicting hash, so it is required for mismatched and absent otherwise.",
"if": {
"properties": { "status": { "const": "mismatched" } },
"required": ["status"]
},
"then": {
"required": ["rebuilt_hash"]
},
"else": {
"not": { "required": ["rebuilt_hash"] }
}
},
{
"$comment": "verified and mismatched are processed results, so processed_at is required.",
"if": {
"properties": {
"status": { "enum": ["verified", "mismatched"] }
},
"required": ["status"]
},
"then": {
"required": ["processed_at"]
}
},
{
"$comment": "unverified is not a processed result, so processed_at must be absent.",
"if": {
"properties": { "status": { "const": "unverified" } },
"required": ["status"]
},
"then": {
"not": { "required": ["processed_at"] }
}
}
]
}
}
}
}
Loading
Loading