{"id":30116418,"url":"https://github.com/authzed/thumper","last_synced_at":"2026-03-10T11:03:47.266Z","repository":{"id":269485685,"uuid":"899720243","full_name":"authzed/thumper","owner":"authzed","description":"Traffic generator for scripting SpiceDB API usage","archived":false,"fork":false,"pushed_at":"2025-08-08T13:38:36.000Z","size":178,"stargazers_count":8,"open_issues_count":8,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-08T15:27:48.683Z","etag":null,"topics":["performance-testing","scale-testing","spicedb","spicedb-client"],"latest_commit_sha":null,"homepage":"https://authzed.com","language":"Go","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/authzed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE-OF-CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-12-06T21:36:14.000Z","updated_at":"2025-07-07T17:43:23.000Z","dependencies_parsed_at":"2025-06-03T21:19:48.561Z","dependency_job_id":"10e5d2d1-e752-4b13-9b32-dcebe492b50a","html_url":"https://github.com/authzed/thumper","commit_stats":null,"previous_names":["authzed/thumper"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/authzed/thumper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/authzed%2Fthumper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/authzed%2Fthumper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/authzed%2Fthumper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/authzed%2Fthumper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/authzed","download_url":"https://codeload.github.com/authzed/thumper/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/authzed%2Fthumper/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269705707,"owners_count":24462175,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-10T02:00:08.965Z","response_time":71,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["performance-testing","scale-testing","spicedb","spicedb-client"],"created_at":"2025-08-10T09:37:28.652Z","updated_at":"2026-03-10T11:03:47.255Z","avatar_url":"https://github.com/authzed.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Thumper\n\nThumper can be used as an artificial traffic generator or/and as an availability probe for [SpiceDB](https://github.com/authzed/spicedb) instances.\n\nIt can issue CheckPermission and CheckBulkPermission requests, Read/Write Relationships, ExpandPermissionTree and LookupResources. It also can expose Prometheus metrics about those operations.\n\n## Usage\n\n1. Install thumper:\n\n    ```sh\n    git clone https://github.com/authzed/thumper.git\n    cd thumper\n    go build -o thumper ./cmd/thumper\n    sudo mv thumper /usr/local/bin/  # Optional if you want to move thumper into $PATH\n    ```\n\n1. Write your script in a YAML file (see [script format](#script-format) down below.)\n\n1. If your script contains schema or relationship writes, run the migration step to set that data up first:\n\n    ```sh\n    thumper migrate --endpoint grpc.authzed.com:443 --token t_some_token ./scripts/schema.yaml\n    ```\n\n1. Run your script as in the following examples:\n\n    ```sh\n    # 5 requests per second against Authzed's hosted SpiceDB with a secure connection:\n    thumper run --qps 5 --endpoint grpc.authzed.com:443 --token t_some_token ./scripts/example.yaml\n\n    # 1 request per second against local SpiceDB with an insecure connection:\n    thumper run --token presharedkeyhere --insecure ./scripts/example.yaml\n    ```\n\n### Script Format\n\nThumper config files are YAML files. These files support Go template preprocessing supported.\n\nThe final YAML generated by the templates must validate with the schema in [schema.yaml](schema.yaml).\n\n#### Example\n\n```yaml\nname: create org, tenant, and add client\nweight: 1\nsteps:\n- op: CheckPermission\n  resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  permission: write_relationships\n  expectNoPermission: true\n  consistency: AtLeastAsFresh\n- op: LookupResources\n  resource: {{ .Prefix }}tenant\n  permission: view_tenant\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  numExpected: 0\n  consistency: AtLeastAsFresh\n- op: WriteRelationships\n  updates:\n  - op: TOUCH\n    resource: {{ .Prefix }}organization:org_{{ randomObjectID }}\n    subject: {{ .Prefix }}platform:plat_{{ randomObjectID }}\n    relation: platform\n  - op: TOUCH\n    resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n    subject: {{ .Prefix }}organization:org_{{ randomObjectID }}\n    relation: organization\n  - op: TOUCH\n    resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n    subject: {{ .Prefix }}client:client_{{ randomObjectID }}#token\n    relation: writer\n  - op: TOUCH\n    resource: {{ .Prefix }}client:client_{{ randomObjectID }}\n    subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n    relation: token\n    caveat:\n      name:  {{ .Prefix }}caveat_name\n      context:\n        bool_field: true\n        string_field: value\n        int_field: 4\n        float_field: 3.14159\n        null_field: null\n        nested_object:\n          abc: def\n        nested_list:\n        - 1\n        - 2\n        - 3\n- op: CheckPermission\n  resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  permission: write_relationships\n  consistency: AtLeastAsFresh\n- op: CheckPermission\n  resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  permission: permission_with_caveat\n  consistency: AtLeastAsFresh\n  context:\n    field_name: field_value\n- op: LookupResources\n  resource: {{ .Prefix }}tenant\n  permission: view_tenant\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  numExpected: 1\n  consistency: AtLeastAsFresh\n- op: WriteRelationships\n  updates:\n  - op: DELETE\n    resource: {{ .Prefix }}organization:org_{{ randomObjectID }}\n    subject: {{ .Prefix }}platform:plat_{{ randomObjectID }}\n    relation: platform\n  - op: DELETE\n    resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n    subject: {{ .Prefix }}organization:org_{{ randomObjectID }}\n    relation: organization\n  - op: DELETE\n    resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n    subject: {{ .Prefix }}client:client_{{ randomObjectID }}#token\n    relation: writer\n  - op: DELETE\n    resource: {{ .Prefix }}client:client_{{ randomObjectID }}\n    subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n    relation: token\n- op: LookupResources\n  resource: {{ .Prefix }}tenant\n  permission: view_tenant\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  numExpected: 0\n  consistency: AtLeastAsFresh\n- op: CheckPermission\n  resource: {{ .Prefix }}tenant:ps_{{ randomObjectID }}\n  subject: {{ .Prefix }}token:t_{{ randomObjectID }}\n  permission: write_relationships\n  expectNoPermission: true\n  consistency: AtLeastAsFresh\n```\n\n#### Types\n\nThe following common types are used in various operations:\n\n| Type | Example(s) | Used In |\n| ---- | ---------- | ------- |\n| Permission/Relation Name | reader, writer, view | * |\n| Object Reference | objecttype:objectid | CheckPermission, ExpandPermissionTree, LookupSubjects, WriteRelationships |\n| Subject Reference | subjecttype:subjectid, subjecttype:subjectid#optionalrelation | CheckPermission, ReadRelationships, DeleteRelationships, ExpandPermissionTree, WriteRelationships |\n| Object Type | objecttype | LookupResources, LookupSubjects |\n| Object Filter | objecttype, objecttype:objectid | ReadRelationships, DeleteRelationships |\n\n#### Go Template Properties\n\nThe following properties are available to be used from within go templates:\n\n##### enumerate(length)\n\nThis function will generate an array with the specific length filled with the natural numbers.\nThis array can be ranged over to repeat a script fragment a number of times with a varying identifier.\n\nExample:\n\n```yaml\nname: many checks\nsteps:\n{{- range $i := enumerate 100 }}\n- op: CheckPermission\n  resource: document:{{ $i }}\n  subject: user:stacy\n  permission: read\n{{- end }}\n```\n\n##### randomObjectID\n\nThis function returns a different random object ID per worker allowing many workers to work on the same flow in parallel. Because this function returns a randomObjectID per worker, it will require you to load a set of scripts for every worker. This can significantly increase the Thumper initialization time for high QPS tests.\n\nExample:\n\n```yaml\nname: check permissions on random document\nweight: 1\nsteps:\n- op: WriteRelationships\n  updates:\n  - op: TOUCH\n    resource: document:{{ randomObjectID }}\n    subject: user:stacy\n    relation: reader\n- op: CheckPermission\n  resource: document:{{ randomObjectID }}\n  subject: user:stacy\n  permission: read\n```\n\n##### Prefix\n\nThis parameter contains the value of the `--prefix` command line parameter followed by a `/`, and can be used to isolate schemas and data between different instances of `thumper`.\n\nExample:\n\n```yaml\nname: check permissions on random tenant\nweight: 1\nsteps:\n- op: WriteRelationships\n  updates:\n  - op: TOUCH\n    resource: {{ .Prefix }}document:1\n    subject: {{ .Prefix }}user:stacy\n    relation: reader\n- op: CheckPermission\n  resource: {{ .Prefix }}document:1\n  subject: {{ .Prefix }}user:stacy\n  permission: read\n```\n\n##### IsMigration\n\nThis parameter contains a boolean that specifies whether the script is being run under the `thumper migrate` command.\nThis can be used to write a script that contains both a migration and the actual test scripts.\n\nExample:\n\n```yaml\n{{- if .IsMigration }}\n---\nname: write schema\nsteps:\n- op: WriteSchema\n  schema: |\n    definition user {}\n    definition document {\n      relation reader: user\n    }\n- op: WriteRelationships\n  updates:\n  - op: TOUCH\n    resource: document:1\n    subject: user:stacy\n    relation: reader\n{{- else }}\n---\nname: check permissions\nweight: 1\nsteps:\n- op: CheckPermission\n  resource: document:1\n  subject: user:stacy\n  permission: reader\n{{- end }}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fauthzed%2Fthumper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fauthzed%2Fthumper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fauthzed%2Fthumper/lists"}