{"id":34837259,"url":"https://github.com/arenadata/yspec","last_synced_at":"2026-05-26T14:37:43.692Z","repository":{"id":53768383,"uuid":"200878271","full_name":"arenadata/yspec","owner":"arenadata","description":"Yaml and JSON structure validator","archived":false,"fork":false,"pushed_at":"2021-03-15T09:36:12.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":3,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-12-27T01:41:19.644Z","etag":null,"topics":["pypi-package"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/yspec/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arenadata.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-06T15:28:45.000Z","updated_at":"2022-01-31T19:39:47.000Z","dependencies_parsed_at":"2022-09-01T14:41:48.613Z","dependency_job_id":null,"html_url":"https://github.com/arenadata/yspec","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/arenadata/yspec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fyspec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fyspec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fyspec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fyspec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arenadata","download_url":"https://codeload.github.com/arenadata/yspec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arenadata%2Fyspec/sbom","scorecard":{"id":206151,"data":{"date":"2025-08-11","repo":{"name":"github.com/arenadata/yspec","commit":"227a23d5d77c34d86eecb8696136813e8d263ff9"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":2,"reason":"Found 3/12 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 21 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T23:49:13.299Z","repository_id":53768383,"created_at":"2025-08-16T23:49:13.299Z","updated_at":"2025-08-16T23:49:13.299Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33525816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["pypi-package"],"created_at":"2025-12-25T16:08:38.610Z","updated_at":"2026-05-26T14:37:43.674Z","avatar_url":"https://github.com/arenadata.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yspec\n\nyspec is a deadly simple checker for structures. It is especially usefull for validation of different yaml/json files\n\n## Usage from cli\n\n```sh\nyspec ./schema.yaml /tmp/data.json\n```\n\nNOTE: yspec able to take yaml/json for schema and for data\n\n## Usage from code\n\n```python\nfrom yspec.checker import check\n\n# Some code that prepares data and rules\n\ncheck(data, rules)\n```\n\n## Schema Format\n\nSchema is a dict of rules. Every rule do some check according to 'match' field. Schema must include 'root' rule which is applied on top object in structure.\n\nFor example structure (in YAML):\n\n```yaml\n---\n- 'string1'\n- 'string2'\n\n```\n\nwill be valid for schema (in YAML):\n\n```yaml\n---\nroot:\n  match: list\n  item: string\n  \nstring:\n  match: string\n```\n\n## Match Rules\n\n### Simple type matches\n\n#### String\n\n```yaml\nmy_awesome_string:\n  match: string\n```\n\n#### Boolean\n\n```yaml\nmy_awesome_bool:\n  match: bool\n```\n\n#### Integer\n\n```yaml\nmy_awesome_int:\n  match: int\n```\n\n#### Float\n\n```yaml\nmy_awesome_float:\n  match: float\n```\n\n#### None\n\n```yaml\nempty_object:\n  match: none\n```\n\n#### Any\n\n```yaml\nany_type:\n  match: any\n```\n\n### Recursion type matches\n\nThere are two of them: dict and list. Both has the same recursion logic. At first we apply some checks on object itself, and then apply another (or the same) rule to childrens (list elements, or values of dict).\n\n#### List\n\n```yaml\nmy_list:\n  match: list\n  item: some_other_rule\n```\n\nList is a recurent type. Fist it checks is the object a list, then it check every element according to rule in 'item' attr.\n\n\n#### Dict\n\n```yaml\nmy_list:\n  match: dict\n  items:\n    key1: string_rule\n    key2: integer_rule\n  default_item: some_other_rule\n  required_items:\n    - key2\n```\n\nThat is a rule that describe a dict that has two keys (key1 and key2). One of keys (key2) is mandatory. Key1 should be checked according to 'string_rule' rule, while any other keys with any other (non key1 or key2) name will be checked according to some_other_rule.\n\n\nIf we has remove default_item\n```yaml\nmy_list:\n  match: dict\n  items:\n    key1: string_rule\n    key2: integer_rule\n  required_items:\n    - key2\n```\n\nA dict could be with two keys (key1, key2) maximum\n\n\n### Sample of simple and recursion matches\n\nSchema:\n\n```yaml\n---\nboolean:\n  match: bool\n\nstring:\n  match: string\n\ninteger:\n  match: int\n\nfloat:\n  match: float\n\nlist:\n  match: list\n  item: string\n\nroot:\n  match: dict\n  items:\n    key1: boolean\n    key2: string\n    key3: integer\n    key4: float\n    key5: list\n```\n\nData:\n```yaml\n---\nkey1: true\nkey2: \"That is a string\"\nkey3: 1\nkey4: 1.0\nkey5:\n  - \"One more string\"\n  - \"Another string\"\n```\n\n### Special matches\n\n#### OneOf match\n\n```yaml\nconstraint_list_item:\n  match: one_of\n  variants:\n    - integer_rule\n    - some_other_rule\n```\n\nOneOf match success if any of rules from \"variants\" success.\n\n#### Set match\n\nSuppose you need to check your little list of fruits:\n\n```yaml\n---\n- apple\n- plum\n```\n\nYou can use Set match for it. In variants clause of Set match you list all\nposible values for this type:\n\n```yaml\n---\nroot:\n  match: list\n  item: fruits\n\nfruits:\n  match: set\n  variants:\n    - apple\n    - orange\n    - plum\n```\n\n#### Dict key selection\n\nSome times you need to do a separate checks for dict that have some key/value pair.\n\nFor example you have the following data:\n```yaml\n---\n- type: type1\n  payload:\n    - 1\n    - 1\n- type: type2\n  payload:\n    - \"that is a string\"\n    - \"that is a string2\"\n```\n\nIn that example you have a dict wich has diffent payload depends of type key. That is possible to describe with following schema:\n\n```yaml\n---\nroot:\n  match: list\n  item: list_item\n\nlist_item:\n  match: dict_key_selection\n  selector: type\n  variants:\n    type1: dict_with_int\n    type2: dict_with_string\n\ndict_with_int:\n  match: dict\n  items:\n    type: string\n    payload: list_of_int\n  required_items:\n    - type\n    - payload\n\ndict_with_string:\n  match: dict\n  items:\n    type: string\n    payload: list_of_string\n  required_items:\n    - type\n    - payload\n  \n\nlist_of_int:\n  match: list\n  item: int\n  \nint:\n  match: int\n  \nlist_of_string:\n  match: list\n  item: string\n  \nstring:\n  match: string\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farenadata%2Fyspec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farenadata%2Fyspec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farenadata%2Fyspec/lists"}