├── .github └── workflows │ ├── cla.yaml │ ├── lint.yaml │ └── test.yaml ├── .pre-commit-config.yaml ├── .yamllint ├── CODE-OF-CONDUCT.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── DCO ├── LICENSE ├── NOTICE ├── README.md ├── authzed-dedicated-metrics ├── datadog │ ├── otel-config.yaml │ └── readme.md ├── otel-collector │ ├── env-vars.sh │ ├── otel-collector-config.yaml │ ├── readme.md │ └── run-otel-collector.sh ├── prometheus-grafana │ ├── README.md │ ├── compose.yaml │ ├── grafana │ │ └── datasource.yml │ └── prometheus │ │ └── prometheus.yml └── readme.md ├── code-examples └── go │ ├── expire │ ├── go.mod │ ├── go.sum │ ├── main.go │ └── schema │ └── export-bulk │ ├── go.mod │ ├── go.sum │ └── main.go ├── datastores ├── README.md ├── crdb.yml ├── memory.yml ├── mysql.yml ├── postgres.yml ├── spanner.yml └── spanner │ ├── Dockerfile.spanner │ └── spanner-init ├── github-actions ├── README.md ├── integration-tests.yaml └── validate-schema.yaml ├── integration-testing ├── README.md ├── go.mod ├── go.sum └── main_test.go ├── kubernetes └── example.yaml ├── notebooks └── rag │ ├── rag.ipynb │ └── requirements.txt ├── observability └── simple-datadog │ ├── .gitignore │ ├── README.md │ ├── all_metrics.txt │ ├── conf.d │ └── openmetrics.d │ │ └── conf.yaml │ ├── datadog.yaml │ ├── docker-compose.yml │ ├── placeholder.env │ └── spicedb-dashboard.json ├── schemas ├── basic-rbac │ ├── README.md │ └── schema-and-data.yaml ├── caveats │ ├── README.md │ └── schema-and-data.yaml ├── docs-style-sharing │ ├── README.md │ └── schema-and-data.yaml ├── google-iam │ ├── README.md │ └── schema-and-data.yaml ├── multiple-validation-files │ ├── README.md │ ├── schema.zed │ └── validations │ │ ├── admin-role.yaml │ │ └── reader-role.yaml ├── superuser │ ├── README.md │ └── schema-and-data.yaml └── user-defined-roles │ ├── README.md │ └── schema-and-data.yaml ├── spicedb-as-library ├── go.mod ├── go.sum └── main.go └── tracing ├── README.md ├── docker-compose.yaml ├── grafana-datasources.yaml ├── otel-config.yaml ├── schema.zed └── tempo.yaml /.github/workflows/cla.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CLA" 3 | on: # yamllint disable-line rule:truthy 4 | issue_comment: 5 | types: 6 | - "created" 7 | pull_request_target: 8 | types: 9 | - "opened" 10 | - "closed" 11 | - "synchronize" 12 | jobs: 13 | cla: 14 | name: "Check Signature" 15 | runs-on: "ubuntu-latest" 16 | steps: 17 | - uses: "authzed/actions/cla-check@main" 18 | with: 19 | github_token: "${{ secrets.GITHUB_TOKEN }}" 20 | cla_assistant_token: "${{ secrets.CLA_ASSISTANT_ACCESS_TOKEN }}" 21 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Lint" 3 | on: # yamllint disable-line rule:truthy 4 | push: 5 | branches: 6 | - "main" 7 | pull_request: 8 | branches: ["*"] 9 | jobs: 10 | lint: 11 | name: "Lint" 12 | runs-on: "ubuntu-latest" 13 | steps: 14 | - uses: "actions/checkout@v3" 15 | - uses: "authzed/actions/yaml-lint@main" 16 | - uses: "instrumenta/kubeval-action@5915e4adba5adccac07cb156b82e54c3fed74921" 17 | with: 18 | files: "kubernetes" 19 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Test" 3 | on: # yamllint disable-line rule:truthy 4 | push: 5 | paths: ["integration-testing/**"] 6 | pull_request: 7 | paths: ["integration-testing/**"] 8 | jobs: 9 | integration-testing: 10 | name: "Run Integration Test Example" 11 | runs-on: "ubuntu-latest" 12 | steps: 13 | - uses: "actions/checkout@v3" 14 | - uses: "actions/setup-go@v3" 15 | with: 16 | go-version: "~1.19.1" 17 | - uses: "authzed/actions/go-test@main" 18 | with: 19 | working_directory: "integration-testing" 20 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: "https://github.com/adrienverge/yamllint" 4 | rev: "v1.35.1" 5 | hooks: 6 | - id: "yamllint" 7 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | # vim: ft=yaml 2 | --- 3 | yaml-files: 4 | - "*.yaml" 5 | - "*.yml" 6 | - ".yamllint" 7 | extends: "default" 8 | rules: 9 | quoted-strings: "enable" 10 | line-length: "disable" 11 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | - The use of sexualized language or imagery 10 | - Personal attacks 11 | - Trolling or insulting/derogatory comments 12 | - Public or private harassment 13 | - Publishing other’s private information, such as physical or electronic addresses, without explicit permission 14 | - Other unethical or unprofessional conduct 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. 17 | By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. 18 | Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 19 | 20 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 21 | 22 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 23 | 24 | This Code of Conduct is adapted from the Contributor Covenant, version 1.2.0, available [here](https://www.contributor-covenant.org/version/1/2/0/code-of-conduct.html) 25 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @authzed/spicedb-maintainers 2 | docker-compose/* @authzed/spicedb-maintainers @bryanhuhta 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ## Communication 4 | 5 | - Issues: [GitHub](https://github.com/authzed/spicedb/issues) 6 | - Email: [Google Groups](https://groups.google.com/g/authzed-oss) 7 | - Discord: [Zanzibar Discord](https://discord.gg/jTysUaxXzM) 8 | 9 | All communication must follow our [Code of Conduct]. 10 | 11 | [Code of Conduct]: CODE-OF-CONDUCT.md 12 | 13 | ## Creating issues 14 | 15 | If any part of the project has a bug or documentation mistakes, please let us know by opening an issue. 16 | All bugs and mistakes are considered very seriously, regardless of complexity. 17 | 18 | Before creating an issue, please check that an issue reporting the same problem does not already exist. 19 | To make the issue accurate and easy to understand, please try to create issues that are: 20 | 21 | - Unique -- do not duplicate existing bug report. 22 | Duplicate bug reports will be closed. 23 | - Specific -- include as much details as possible: which version, what environment, what configuration, etc. 24 | - Reproducible -- include the steps to reproduce the problem. 25 | Some issues might be hard to reproduce, so please do your best to include the steps that might lead to the problem. 26 | - Isolated -- try to isolate and reproduce the bug with minimum dependencies. 27 | It would significantly slow down the speed to fix a bug if too many dependencies are involved in a bug report. 28 | Debugging external systems that rely on this project is out of scope, but guidance or help using the project itself is fine. 29 | - Scoped -- one bug per report. 30 | Do not follow up with another bug inside one report. 31 | 32 | It may be worthwhile to read [Elika Etemad’s article on filing good bug reports][filing-good-bugs] before creating a bug report. 33 | 34 | Maintainers might ask for further information to resolve an issue. 35 | 36 | [filing-good-bugs]: http://fantasai.inkedblade.net/style/talks/filing-good-bugs/ 37 | 38 | ## Contribution flow 39 | 40 | This is a rough outline of what a contributor's workflow looks like: 41 | 42 | - Create an issue 43 | - Fork the project 44 | - Create a [feature branch] 45 | - Push changes to your branch 46 | - Submit a pull request 47 | - Respond to feedback from project maintainers 48 | - Rebase to squash related and fixup commits 49 | - Get LGTM from reviewer(s) 50 | - Merge with a merge commit 51 | 52 | Creating new issues is one of the best ways to contribute. 53 | You have no obligation to offer a solution or code to fix an issue that you open. 54 | If you do decide to try and contribute something, please submit an issue first so that a discussion can occur to avoid any wasted efforts. 55 | 56 | [feature branch]: https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow 57 | 58 | ## Legal requirements 59 | 60 | In order to protect both you and ourselves, all commits will require an explicit sign-off that acknowledges the [DCO]. 61 | 62 | Sign-off commits end with the following line: 63 | 64 | ```git 65 | Signed-off-by: Random J Developer 66 | ``` 67 | 68 | This can be done by using the `--signoff` (or `-s` for short) git flag to append this automatically to your commit message. 69 | If you have already authored a commit that is missing the signed-off, you can amend or rebase your commits and force push them to GitHub. 70 | 71 | [DCO]: /DCO 72 | 73 | ## Common tasks 74 | 75 | ### Testing 76 | 77 | In order to build and test the project, the [latest stable version of Go] and knowledge of a [working Go environment] are required. 78 | 79 | [latest stable version of Go]: https://golang.org/dl 80 | [working Go environment]: https://golang.org/doc/code.html 81 | 82 | ```sh 83 | go test -v ./... 84 | ``` 85 | 86 | ### Adding dependencies 87 | 88 | This project does not use anything other than the standard [Go modules] toolchain for managing dependencies. 89 | 90 | [Go modules]: https://golang.org/ref/mod 91 | 92 | ```sh 93 | go get github.com/org/newdependency@version 94 | ``` 95 | 96 | Continuous integration enforces that `go mod tidy` has been run. 97 | 98 | ### Updating generated Protobuf code 99 | 100 | All [Protobuf] code is managed using [buf]. 101 | The [shebang] at the top of `buf.gen.yaml` contains the [Buf Registry ref] that will be generated. 102 | You can regenerate the code by executing `buf.gen.yaml`: 103 | 104 | [Protobuf]: https://developers.google.com/protocol-buffers/ 105 | [buf]: https://docs.buf.build/installation 106 | [shebang]: https://en.wikipedia.org/wiki/Shebang_(Unix) 107 | [Buf Registry ref]: https://buf.build/authzed/api/history 108 | 109 | ```sh 110 | ./buf.gen.yaml 111 | ``` 112 | -------------------------------------------------------------------------------- /DCO: -------------------------------------------------------------------------------- 1 | Developer Certificate of Origin 2 | Version 1.1 3 | 4 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 5 | 1 Letterman Drive 6 | Suite D4700 7 | San Francisco, CA, 94129 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this 10 | license document, but changing it is not allowed. 11 | 12 | 13 | Developer's Certificate of Origin 1.1 14 | 15 | By making a contribution to this project, I certify that: 16 | 17 | (a) The contribution was created in whole or in part by me and I 18 | have the right to submit it under the open source license 19 | indicated in the file; or 20 | 21 | (b) The contribution is based upon previous work that, to the best 22 | of my knowledge, is covered under an appropriate open source 23 | license and I have the right under that license to submit that 24 | work with modifications, whether created in whole or in part 25 | by me, under the same open source license (unless I am 26 | permitted to submit under a different license), as indicated 27 | in the file; or 28 | 29 | (c) The contribution was provided directly to me by some other 30 | person who certified (a), (b) or (c) and I have not modified 31 | it. 32 | 33 | (d) I understand and agree that this project and the contribution 34 | are public and that a record of the contribution (including all 35 | personal information I submit with it, including my sign-off) is 36 | maintained indefinitely and may be redistributed consistent with 37 | this project or the open source license(s) involved. 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | SpiceDB 2 | Copyright 2022 Authzed, Inc 3 | 4 | This product includes software developed at 5 | Authzed, Inc. (https://www.authzed.com/). 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | [![Docs](https://img.shields.io/badge/docs-authzed.com-%234B4B6C "Authzed Documentation")](https://docs.authzed.com) 4 | [![Discord Server](https://img.shields.io/discord/844600078504951838?color=7289da&logo=discord "Discord Server")](https://discord.gg/jTysUaxXzM) 5 | [![Twitter](https://img.shields.io/twitter/follow/authzed?color=%23179CF0&logo=twitter&style=flat-square "@authzed on Twitter")](https://twitter.com/authzed) 6 | 7 | This repository houses various examples for various aspects of SpiceDB. 8 | 9 | [SpiceDB] is an open source database system for managing security-critical application permissions inspired by Google's [Zanzibar] paper. 10 | 11 | Developers create a schema that models their permissions requirements and use a [client library] to apply the schema to the database, insert data into the database, and query the data to efficiently check permissions in their applications. 12 | 13 | [SpiceDB]: https://github.com/authzed/spicedb 14 | [Zanzibar]: https://authzed.com/blog/what-is-zanzibar/ 15 | [client library]: https://github.com/orgs/authzed/repositories?q=client+library 16 | 17 | Examples in this repository include: 18 | 19 | - Schema 20 | - CI/CD Workflows 21 | 22 | Have questions? Join our [Discord]. 23 | 24 | Looking to contribute? See [CONTRIBUTING.md]. 25 | 26 | [Discord]: https://authzed.com/discord 27 | [CONTRIBUTING.md]: https://github.com/authzed/spicedb/blob/main/CONTRIBUTING.md 28 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/datadog/otel-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | receivers: 3 | prometheus: 4 | config: 5 | scrape_configs: 6 | - job_name: "prometheus" 7 | metrics_path: "/api/v1alpha/metrics" 8 | scrape_interval: "15s" 9 | static_configs: 10 | - targets: [""] 11 | basic_auth: 12 | username: "" 13 | password: "" 14 | exporters: 15 | datadog: 16 | api: 17 | site: "" 18 | key: "" 19 | service: 20 | pipelines: 21 | metrics: 22 | receivers: ["prometheus"] 23 | processors: [] 24 | exporters: ["datadog"] 25 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/datadog/readme.md: -------------------------------------------------------------------------------- 1 | 2 | # OpenTelemetry Collector for AuthZed Dedicated Metrics 3 | 4 | This guide explains how to deploy the OpenTelemetry Collector Contributor image to collect metrics from AuthZed Dedicated and push them to Datadog. 5 | 6 | ## Prerequisites 7 | 8 | - Docker installed on your machine. 9 | - Access to AuthZed Dedicated instance. 10 | - Datadog API key. 11 | 12 | ## Deployment 13 | 14 | ### Step 1: Prepare the Configuration File 15 | 16 | Create a configuration file named `otel-config.yaml` with the following content. Be sure to replace the placeholders with your actual values: 17 | 18 | ```yaml 19 | receivers: 20 | prometheus: 21 | config: 22 | scrape_configs: 23 | - job_name: 'prometheus' 24 | metrics_path: /api/v1alpha/metrics 25 | scrape_interval: 15s 26 | static_configs: 27 | - targets: [''] 28 | basic_auth: 29 | username: '' 30 | password: '' 31 | 32 | exporters: 33 | datadog: 34 | api: 35 | site: "" 36 | key: "" 37 | 38 | service: 39 | pipelines: 40 | metrics: 41 | receivers: [prometheus] 42 | processors: [] 43 | exporters: [datadog] 44 | ``` 45 | 46 | ### Step 2: Deploy the OpenTelemetry Collector 47 | 48 | Run the following Docker command to deploy the OpenTelemetry Collector: 49 | 50 | ```bash 51 | docker run --rm -d --name otel-collector -v "$(pwd)/otel-config.yaml:/otel-config.yaml" otel/opentelemetry-collector-contrib:latest --config=/otel-config.yaml 52 | ``` 53 | 54 | This command will start the OpenTelemetry Collector, which will begin scraping metrics from your AuthZed Dedicated instance and exporting them to Datadog. 55 | 56 | ### Step 3: Verify the Metrics in Datadog 57 | 58 | Log in to your Datadog account and navigate to the metrics section. You should see the metrics from your AuthZed Dedicated instance being reported. 59 | 60 | ## Configuration Details 61 | 62 | - ``: Replace with the URL of your AuthZed Dedicated instance (e.g., `example.app.aws.authzed.net`). 63 | - `` and ``: Replace with the username and password for basic authentication to access your AuthZed metrics endpoint. 64 | - ``: Replace with your Datadog site URL (e.g., `us5.datadoghq.com`). 65 | - ``: Replace with your Datadog API key. 66 | 67 | ## Troubleshooting 68 | 69 | If you encounter issues: 70 | 71 | - Ensure that the `otel-config.yaml` file is correctly configured and that all placeholders are replaced with actual values. 72 | - Check the Docker container logs for any errors: 73 | 74 | ``` 75 | docker logs otel-collector 76 | ``` 77 | 78 | - Verify that your AuthZed Dedicated instance is accessible and that the credentials are correct. 79 | - Confirm that your Datadog API key and site are correct. -------------------------------------------------------------------------------- /authzed-dedicated-metrics/otel-collector/env-vars.sh: -------------------------------------------------------------------------------- 1 | export AUTHZED_DEDICATED_HOST='' 2 | export PROMETHEUS_USERNAME='' 3 | export PROMETHEUS_PASSWORD='' 4 | export OTEL_EXPORTER_OTLP_ENDPOINT="https://:443" 5 | export OTEL_EXPORTER_OTLP_HEADERS="your-service-key" 6 | export OTEL_SERVICE_NAME="authzed-" 7 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/otel-collector/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | receivers: 3 | prometheus: 4 | config: 5 | scrape_configs: 6 | - job_name: "prometheus" 7 | metrics_path: "/api/v1alpha/metrics" 8 | scrape_interval: "15s" 9 | static_configs: 10 | - targets: ["${AUTHZED_DEDICATED_HOST}"] 11 | basic_auth: 12 | username: ${PROMETHEUS_USERNAME} # yamllint disable-line rule:quoted-strings 13 | password: ${PROMETHEUS_PASSWORD} # yamllint disable-line rule:quoted-strings 14 | exporters: 15 | otlp: 16 | endpoint: ${OTEL_EXPORTER_OTLP_ENDPOINT} # yamllint disable-line rule:quoted-strings 17 | headers: 18 | x-honeycomb-team: ${OTEL_EXPORTER_OTLP_HEADERS} # yamllint disable-line rule:quoted-strings 19 | service: 20 | pipelines: 21 | metrics: 22 | receivers: ["prometheus"] 23 | exporters: ["otlp"] 24 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/otel-collector/readme.md: -------------------------------------------------------------------------------- 1 | 2 | # OpenTelemetry Collector - AuthZed Dedicated 3 | 4 | This repository provides a simple setup for running the OpenTelemetry Collector in a Docker container, configured to scrape metrics from a Prometheus endpoint and export to a metrics collection service. 5 | 6 | ## Prerequisites 7 | 8 | - Docker installed on your machine 9 | - A Prometheus endpoint with valid credentials 10 | - A metrics service account and API key 11 | 12 | ## Setup 13 | 14 | 15 | 2. **Create the `env-vars.sh` File** 16 | 17 | Edit the file named `env-vars.sh` in the root of the repository with the following content: 18 | 19 | ```sh 20 | export PROMETHEUS_USERNAME='' 21 | export PROMETHEUS_PASSWORD='' 22 | export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel-metrics-service-url" 23 | export OTEL_EXPORTER_OTLP_HEADERS="your-service-key" 24 | export OTEL_SERVICE_NAME="authzed-" 25 | ``` 26 | 27 | Replace the placeholder values with your actual credentials and configurations. 28 | 29 | 3. **Create the Configuration File** 30 | 31 | Edit the file named `otel-collector-config.yaml` in the root of the repository. 32 | 33 | 4. **Make the Script Executable** 34 | 35 | Make the `run-otel-collector.sh` script executable: 36 | 37 | ```bash 38 | chmod +x run-otel-collector.sh 39 | ``` 40 | 41 | 5. **Run the Script** 42 | 43 | Run the script to start the OpenTelemetry Collector Docker container with the configured settings: 44 | 45 | ```bash 46 | ./run-otel-collector.sh 47 | ``` 48 | 49 | ## Files 50 | 51 | - `env-vars.sh`: Contains the environment variables for Prometheus and Honeycomb configuration. 52 | - `otel-collector-config.yaml`: Configuration file for the OpenTelemetry Collector. 53 | - `run-otel-collector.sh`: Shell script to load environment variables and run the OpenTelemetry Collector Docker container. 54 | 55 | 56 | ## Contact 57 | 58 | If you have any questions or need further assistance, feel free to open an issue or contact support@authzed.com -------------------------------------------------------------------------------- /authzed-dedicated-metrics/otel-collector/run-otel-collector.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Load environment variables from file 4 | source ./env-vars.sh 5 | 6 | # Check if all necessary environment variables are set 7 | if [[ -z "$PROMETHEUS_USERNAME" || -z "$PROMETHEUS_PASSWORD" || -z "$OTEL_EXPORTER_OTLP_ENDPOINT" || -z "$OTEL_EXPORTER_OTLP_HEADERS" || -z "$OTEL_SERVICE_NAME" ]]; then 8 | echo "One or more environment variables are not set. Please check your env-vars.sh file." 9 | exit 1 10 | fi 11 | 12 | # Run OpenTelemetry Collector Docker container 13 | docker run --rm -it \ 14 | -v $(pwd)/otel-collector-config.yaml:/otel-collector-config.yaml \ 15 | -e PROMETHEUS_USERNAME="$PROMETHEUS_USERNAME" \ 16 | -e PROMETHEUS_PASSWORD="$PROMETHEUS_PASSWORD" \ 17 | -e OTEL_EXPORTER_OTLP_ENDPOINT="$OTEL_EXPORTER_OTLP_ENDPOINT" \ 18 | -e OTEL_EXPORTER_OTLP_HEADERS="$OTEL_EXPORTER_OTLP_HEADERS" \ 19 | -e OTEL_SERVICE_NAME="$OTEL_SERVICE_NAME" \ 20 | otel/opentelemetry-collector:latest \ 21 | --config otel-collector-config.yaml 22 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/prometheus-grafana/README.md: -------------------------------------------------------------------------------- 1 | ### AuthZed Dedicated - Prometheus & Grafana 2 | 3 | ## Configuring Prometheus to Scrape Metrics from AuthZed Dedicated 4 | 5 | To enable Prometheus to scrape metrics from your permission system, configure the `scrape_config` section in prometheus.yml. 6 | 7 | 1. Open `prometheus.yml` in an editor. 8 | 9 | 2. Add the following `scrape_config` section to your configuration file, replacing the placeholder values with your specific details: 10 | 11 | ```yaml 12 | scrape_configs: 13 | - job_name: "exported-metrics-from-[permission-system]" 14 | metrics_path: /api/v1alpha/metrics 15 | basic_auth: 16 | username: "[permission-system]" 17 | password: "[token]" 18 | static_configs: 19 | - targets: 20 | - "[authzed-dashboard-url]" 21 | ``` 22 | 23 | ### Required Values 24 | 25 | - **job_name**: Replace `[permission-system]` with the name of your permission system. This identifies the job in Prometheus. 26 | - Example: `job_name: "exported-metrics-from-my-permission-system"` 27 | 28 | - **metrics_path**: Set to `/api/v1alpha/metrics`. 29 | 30 | - **basic_auth**: 31 | - **username**: Replace `[permission-system]` with the permission system name used for basic authentication. 32 | - Example: `username: "my-permission-system"` 33 | - **password**: Replace `[token]` with the token for basic authentication. 34 | - Example: `password: "doGXlyJdtjZHOdCw486t"` 35 | 36 | - **static_configs**: 37 | - **targets**: Replace `[authzed-dashboard-url]` with the URL of your Authzed dashboard. 38 | 39 | - Example: `targets: ["https://app.demo.aws.authzed.net"]` 40 | 41 | ### Example Configuration 42 | 43 | Here's an example of a filled-out configuration: 44 | 45 | ```yaml 46 | scrape_configs: 47 | - job_name: "exported-metrics-from-my-permission-system" 48 | metrics_path: /api/v1alpha/metrics 49 | basic_auth: 50 | username: "my-permission-system" 51 | password: "my-secret-token" 52 | static_configs: 53 | - targets: 54 | - "https://app.demo.aws.authzed.net" 55 | ``` 56 | 57 | 3. Save prometheus.yml 58 | 59 | 4. Run `docker compose up` 60 | 61 | ### Ports: 62 | 63 | Prometheus: 9090 64 | Grafana: 3000 65 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/prometheus-grafana/compose.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | services: 3 | prometheus: 4 | image: "prom/prometheus:latest" 5 | container_name: "prometheus" 6 | command: 7 | - "--config.file=/etc/prometheus/prometheus.yml" 8 | ports: 9 | - "9090:9090" 10 | restart: "unless-stopped" 11 | volumes: 12 | - "./prometheus:/etc/prometheus" 13 | - "prom_data:/prometheus" 14 | grafana: 15 | image: "grafana/grafana:latest" 16 | container_name: "grafana" 17 | ports: 18 | - "3000:3000" 19 | restart: "unless-stopped" 20 | environment: 21 | - "GF_SECURITY_ADMIN_USER=admin" 22 | - "GF_SECURITY_ADMIN_PASSWORD=grafana" 23 | volumes: 24 | - "./grafana:/etc/grafana/provisioning/datasources" 25 | volumes: 26 | prom_data: 27 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/prometheus-grafana/grafana/datasource.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: "1" 3 | datasources: 4 | - name: "Prometheus" 5 | type: "prometheus" 6 | url: "http://prometheus:9090" 7 | isDefault: true 8 | access: "proxy" 9 | editable: true 10 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/prometheus-grafana/prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | --- 2 | global: 3 | scrape_interval: "15s" 4 | scrape_timeout: "10s" 5 | evaluation_interval: "15s" 6 | alerting: 7 | alertmanagers: 8 | - static_configs: 9 | - targets: [] 10 | scrape_configs: 11 | - job_name: "prometheus" 12 | honor_timestamps: true 13 | scrape_interval: "15s" 14 | scrape_timeout: "10s" 15 | metrics_path: "/metrics" 16 | scheme: "http" 17 | static_configs: 18 | - targets: 19 | - "localhost:9090" 20 | - job_name: "exported-metrics-from-[permission-system]" 21 | metrics_path: "/api/v1alpha/metrics" 22 | basic_auth: 23 | username: "[permission-system]" 24 | password: "[token]" 25 | static_configs: 26 | - targets: 27 | - "[authzed-dashboard-url]" 28 | -------------------------------------------------------------------------------- /authzed-dedicated-metrics/readme.md: -------------------------------------------------------------------------------- 1 | # AuthZed Dedicated Metrics 2 | 3 | This collection of examples is designed to help you collect metrics from AuthZed Dedicated instances. 4 | 5 | 6 | ## What's Inside 7 | 8 | - **OpenTelemetry Collector Configuration**: Examples on how to use the OpenTelemetry Collector to scrape metrics from AuthZed Dedicated and export them to monitoring platforms like Datadog. 9 | - **Prometheus Configurations**: Preconfigured examples for setting up Prometheus to collect metrics from your AuthZed instances. 10 | - **Grafana Dashboard**: Sample dashboards for visualizing the collected metrics, providing insights into the performance and health of your AuthZed Dedicated instance. 11 | 12 | ## Contributing 13 | 14 | Contributions are welcome! If you have an example or improvement to share, feel free to submit a pull request. 15 | 16 | ## Support 17 | 18 | If you encounter any issues or have questions, please open an issue in this repository or e-mail support@authzed.com 19 | -------------------------------------------------------------------------------- /code-examples/go/expire/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/authzed/examples/code-examples/go/expire 2 | 3 | go 1.23.4 4 | 5 | require ( 6 | github.com/authzed/authzed-go v1.2.0 7 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b 8 | google.golang.org/grpc v1.69.2 9 | google.golang.org/protobuf v1.36.0 10 | ) 11 | 12 | require ( 13 | cloud.google.com/go/compute/metadata v0.5.2 // indirect 14 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 15 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect 18 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect 19 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect 20 | github.com/jzelinskie/stringz v0.0.3 // indirect 21 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect 22 | github.com/pmezard/go-difflib v1.0.0 // indirect 23 | github.com/samber/lo v1.47.0 // indirect 24 | github.com/stretchr/testify v1.10.0 // indirect 25 | golang.org/x/net v0.31.0 // indirect 26 | golang.org/x/sys v0.27.0 // indirect 27 | golang.org/x/text v0.20.0 // indirect 28 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect 29 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /code-examples/go/expire/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= 3 | cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/authzed/authzed-go v1.2.0 h1:Ep1sRJMxcArB++kYqHbYKQCb/GgdGZI0cW4gZrJ1K40= 6 | github.com/authzed/authzed-go v1.2.0/go.mod h1:4lkFxvaCISG1roRdnUt35/Sk1StVuMD1QCwTd/BcWcM= 7 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey9sZasO7b6BWLAJnHHvb79fvWCXwxw= 8 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ= 9 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 10 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 11 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 12 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 13 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= 14 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= 15 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 16 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 17 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 19 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 21 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 22 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 23 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 24 | github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= 25 | github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= 26 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 27 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 28 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 29 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 30 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 31 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 32 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 33 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 34 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 35 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 36 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 37 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 38 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 39 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 40 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 41 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 42 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 43 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 44 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 45 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 46 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= 47 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= 48 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= 49 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= 50 | github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= 51 | github.com/jzelinskie/stringz v0.0.3/go.mod h1:hHYbgxJuNLRw91CmpuFsYEOyQqpDVFg8pvEh23vy4P0= 52 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 53 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 54 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 55 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 56 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 57 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 58 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 59 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 60 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 61 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 62 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 63 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= 64 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= 65 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 66 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 67 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 68 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 69 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 70 | github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= 71 | github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= 72 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 73 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 74 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 75 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 76 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 77 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 78 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 79 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 80 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 81 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 82 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 83 | go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= 84 | go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= 85 | go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= 86 | go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= 87 | go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= 88 | go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= 89 | go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= 90 | go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= 91 | go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= 92 | go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= 93 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 94 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 95 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 96 | go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 97 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 98 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 99 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 100 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 101 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 102 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 103 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 104 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 105 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 106 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 107 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 108 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 109 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 110 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 111 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 112 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 113 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 114 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 115 | golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= 116 | golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 117 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 118 | golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= 119 | golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 120 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 121 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 122 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 123 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 124 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 125 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 126 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 127 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 128 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 129 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 130 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 131 | golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= 132 | golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 133 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 134 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 135 | golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= 136 | golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 137 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 138 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 139 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 140 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 141 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 142 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 143 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 144 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 145 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 146 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 147 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 148 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 149 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 150 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 151 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 152 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 153 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 154 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 155 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= 156 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= 157 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= 158 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= 159 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 160 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 161 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 162 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 163 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 164 | google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= 165 | google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= 166 | google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= 167 | google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 168 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 169 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 170 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 171 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 172 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 173 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 174 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 175 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 176 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 177 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 178 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 179 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 180 | -------------------------------------------------------------------------------- /code-examples/go/expire/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "time" 7 | 8 | v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 9 | "github.com/authzed/authzed-go/v1" 10 | "github.com/authzed/grpcutil" 11 | "google.golang.org/grpc" 12 | "google.golang.org/grpc/credentials/insecure" 13 | "google.golang.org/protobuf/types/known/timestamppb" 14 | ) 15 | 16 | func main() { 17 | client, err := authzed.NewClient( 18 | //this example uses a local SpiceDB without TLS 19 | "localhost:50051", 20 | grpcutil.WithInsecureBearerToken("abc123"), 21 | grpc.WithTransportCredentials(insecure.NewCredentials()), 22 | ) 23 | if err != nil { 24 | log.Fatalf("unable to initialize client: %s", err) 25 | } 26 | 27 | now := time.Now() 28 | 29 | //sets the expirationTime 20 seconds from now 30 | expirationTime := now.Add(20 * time.Second) 31 | 32 | request := &v1.WriteRelationshipsRequest{Updates: []*v1.RelationshipUpdate{ 33 | { 34 | Operation: v1.RelationshipUpdate_OPERATION_CREATE, 35 | Relationship: &v1.Relationship{ 36 | Resource: &v1.ObjectReference{ 37 | ObjectType: "document", 38 | ObjectId: "1", 39 | }, 40 | Relation: "viewer", 41 | Subject: &v1.SubjectReference{ 42 | Object: &v1.ObjectReference{ 43 | ObjectType: "user", 44 | ObjectId: "tim", 45 | }, 46 | }, 47 | //OptionalExpiresAt specifies the expiration time. 48 | OptionalExpiresAt: timestamppb.New(expirationTime), 49 | }, 50 | }, 51 | }} 52 | 53 | _, err = client.WriteRelationships(context.Background(), request) 54 | if err != nil { 55 | log.Fatalf("failed to write relationship: %s", err) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /code-examples/go/expire/schema: -------------------------------------------------------------------------------- 1 | use expiration 2 | 3 | definition user {} 4 | 5 | definition document { 6 | relation viewer: user with expiration 7 | 8 | permission view = viewer 9 | } -------------------------------------------------------------------------------- /code-examples/go/export-bulk/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/authzed/examples/code-examples/go/export-bulk 2 | 3 | go 1.23.4 4 | 5 | require ( 6 | github.com/authzed/authzed-go v1.2.0 7 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b 8 | google.golang.org/grpc v1.69.0 9 | ) 10 | 11 | require ( 12 | cloud.google.com/go/compute/metadata v0.5.2 // indirect 13 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 14 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect 15 | github.com/davecgh/go-spew v1.1.1 // indirect 16 | github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect 17 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect 18 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 // indirect 19 | github.com/jzelinskie/stringz v0.0.3 // indirect 20 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect 21 | github.com/pmezard/go-difflib v1.0.0 // indirect 22 | github.com/samber/lo v1.47.0 // indirect 23 | github.com/stretchr/testify v1.10.0 // indirect 24 | golang.org/x/net v0.31.0 // indirect 25 | golang.org/x/sys v0.27.0 // indirect 26 | golang.org/x/text v0.20.0 // indirect 27 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect 28 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect 29 | google.golang.org/protobuf v1.35.2 // indirect 30 | gopkg.in/yaml.v3 v3.0.1 // indirect 31 | ) 32 | -------------------------------------------------------------------------------- /code-examples/go/export-bulk/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= 3 | cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/authzed/authzed-go v1.2.0 h1:Ep1sRJMxcArB++kYqHbYKQCb/GgdGZI0cW4gZrJ1K40= 6 | github.com/authzed/authzed-go v1.2.0/go.mod h1:4lkFxvaCISG1roRdnUt35/Sk1StVuMD1QCwTd/BcWcM= 7 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b h1:wbh8IK+aMLTCey9sZasO7b6BWLAJnHHvb79fvWCXwxw= 8 | github.com/authzed/grpcutil v0.0.0-20240123194739-2ea1e3d2d98b/go.mod h1:s3qC7V7XIbiNWERv7Lfljy/Lx25/V1Qlexb0WJuA8uQ= 9 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 10 | github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 11 | github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 12 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 13 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= 14 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= 15 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 16 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 17 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 18 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 19 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 21 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 22 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 23 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 24 | github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= 25 | github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= 26 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 27 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 28 | github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= 29 | github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 30 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 31 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 32 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 33 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 34 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 35 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 36 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 37 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 38 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 39 | github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 40 | github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 41 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 42 | github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 43 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 44 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 45 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 46 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= 47 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= 48 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= 49 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= 50 | github.com/jzelinskie/stringz v0.0.3 h1:0GhG3lVMYrYtIvRbxvQI6zqRTT1P1xyQlpa0FhfUXas= 51 | github.com/jzelinskie/stringz v0.0.3/go.mod h1:hHYbgxJuNLRw91CmpuFsYEOyQqpDVFg8pvEh23vy4P0= 52 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 53 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 54 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 55 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 56 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 57 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 58 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 59 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 60 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 61 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 62 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 63 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= 64 | github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= 65 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 66 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 67 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 68 | github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= 69 | github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= 70 | github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= 71 | github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= 72 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 73 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 74 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 75 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 76 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 77 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 78 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 79 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 80 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 81 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 82 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 83 | go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= 84 | go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= 85 | go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= 86 | go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= 87 | go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= 88 | go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= 89 | go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc= 90 | go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8= 91 | go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= 92 | go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= 93 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 94 | go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= 95 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 96 | go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= 97 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 98 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 99 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 100 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 101 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 102 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 103 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 104 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 105 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 106 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 107 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 108 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 109 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 110 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 111 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 112 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 113 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 114 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 115 | golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= 116 | golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= 117 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 118 | golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= 119 | golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 120 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 121 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 122 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 123 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 124 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 125 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 126 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 127 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 128 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 129 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 130 | golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 131 | golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= 132 | golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 133 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 134 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 135 | golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= 136 | golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= 137 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 138 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 139 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 140 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 141 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 142 | golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 143 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 144 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 145 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 146 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 147 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 148 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 149 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 150 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 151 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 152 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 153 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 154 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 155 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= 156 | google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= 157 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA= 158 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= 159 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 160 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 161 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 162 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 163 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 164 | google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI= 165 | google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= 166 | google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= 167 | google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 168 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 169 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 170 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 171 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 172 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 173 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 174 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 175 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 176 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 177 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 178 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 179 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 180 | -------------------------------------------------------------------------------- /code-examples/go/export-bulk/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "io" 7 | "log" 8 | "time" 9 | 10 | v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 11 | "github.com/authzed/authzed-go/v1" 12 | "github.com/authzed/grpcutil" 13 | "google.golang.org/grpc" 14 | "google.golang.org/grpc/credentials/insecure" 15 | ) 16 | 17 | const spicedbEndpoint = "localhost:50051" 18 | const maxRetries = 5 19 | 20 | func main() { 21 | client, err := authzed.NewClient( 22 | spicedbEndpoint, 23 | grpcutil.WithInsecureBearerToken("abc123"), 24 | grpc.WithTransportCredentials(insecure.NewCredentials()), 25 | ) 26 | if err != nil { 27 | log.Fatalf("unable to initialize client: %s", err) 28 | } 29 | 30 | ctx, cancel := context.WithCancel(context.Background()) 31 | defer cancel() 32 | 33 | var cursor *v1.Cursor 34 | var exportResults []*v1.Relationship 35 | 36 | totalProcessed := 0 37 | 38 | var endOfFile bool 39 | 40 | request := &v1.ExportBulkRelationshipsRequest{ 41 | OptionalLimit: 1000, 42 | } 43 | 44 | retries := 0 45 | 46 | for { 47 | if cursor != nil { 48 | request.OptionalCursor = cursor 49 | } 50 | stream, err := client.PermissionsServiceClient.ExportBulkRelationships(ctx, request) 51 | if err != nil { 52 | retry(&retries, err) 53 | continue 54 | } 55 | 56 | for { 57 | item, err := stream.Recv() 58 | if errors.Is(err, io.EOF) { 59 | endOfFile = true 60 | break 61 | } 62 | if err != nil { 63 | log.Printf("Stream error: %s", err) 64 | retry(&retries, err) 65 | break 66 | } 67 | 68 | exportResults = append(exportResults, item.Relationships...) 69 | 70 | cursor = item.AfterResultCursor 71 | 72 | totalProcessed += len(item.Relationships) 73 | log.Printf("Processed total: %d.", totalProcessed) 74 | 75 | } 76 | 77 | if endOfFile { 78 | break 79 | } 80 | } 81 | 82 | log.Printf("Export complete: %d relationships retrieved\n", totalProcessed) 83 | 84 | } 85 | 86 | func retry(retries *int, err error) { 87 | *retries++ 88 | if *retries >= maxRetries { 89 | log.Fatalf("Max retries reached: %s", err) 90 | } 91 | log.Printf("Retrying (%d/%d) after error: %s", *retries, maxRetries, err) 92 | time.Sleep(time.Second * time.Duration(*retries)) // Backoff 93 | } 94 | -------------------------------------------------------------------------------- /datastores/README.md: -------------------------------------------------------------------------------- 1 | # Quickstart examples 2 | 3 | This directory contains a variety of quickstart examples to start SpiceDB with various storage engines. 4 | 5 | > **Warning** 6 | > These examples are **not** production-ready and are provided purely for local testing only. 7 | 8 | ## Usage 9 | 10 | To use a quickstart, run: 11 | 12 | ```shell 13 | docker compose -f up 14 | ``` 15 | 16 | For example, running the Postgres quickstart: 17 | 18 | ```shell 19 | docker compose -f postgres.yml up 20 | ``` 21 | 22 | Use `Ctrl+C` to stop the quickstart and use 23 | 24 | ```shell 25 | docker compose -f postgres.yml down 26 | ``` 27 | 28 | to shut down the containers. 29 | 30 | > **Note** 31 | > Most quickstarts have configuration services in them to properly set up the storage engine. This means it may take a minute or so before the quickstart is ready to use. 32 | 33 | ## Available quickstarts 34 | 35 | - [CockroachDB](crdb.yml) 36 | - [Memory](memory.yml) 37 | - [MySQL](mysql.yml) 38 | - [Postgres](postgres.yml) 39 | - [Spanner](spanner.yml) 40 | -------------------------------------------------------------------------------- /datastores/crdb.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Docker: docker compose -f crdb.yml up --scale crdb=3 3 | # Zed: zed context set example-crdb localhost:50051 foobar --insecure 4 | # 5 | # This runs SpiceDB, using CockroachDB as the storage engine. SpiceDB will not 6 | # have any schema written to it. 7 | # 8 | # This compose example is designed to support CRDB clusters. In order 9 | # to properly form a CRDB cluster, the CLI must be invoked with: --scale=3 10 | # You can set scale to any number of nodes, or skip to spin up one single node. 11 | # 12 | # - init_cluster runs tells CRDB to form the cluster 13 | # - init_database creates the logical database used by spicedb 14 | # - migrate runs "spicedb migrate head", which initializes the SpiceDB schema definition 15 | # 16 | # Note: if you specify a project name with the -p flag, the DNS of the CRDB hosts will change 17 | # and the cluster won't form 18 | # 19 | # SpiceDB settings: 20 | # pre-shared key: foobar 21 | # dashboard address: http://localhost:8080 22 | # metrics address: http://localhost:9090 23 | # grpc address: http://localhost:50051 24 | # 25 | # CockroachDB settings: 26 | # user: root 27 | # password: secret 28 | # port: 26257 29 | # dashboard address: http://localhost:8081 30 | # sql DSN: postgresql://root:secret@crdb:26257/spicedb?sslmode=disable 31 | 32 | version: "3" 33 | 34 | services: 35 | spicedb: 36 | image: "authzed/spicedb" 37 | command: "serve" 38 | restart: "always" 39 | ports: 40 | - "8080:8080" 41 | - "9090:9090" 42 | - "50051:50051" 43 | environment: 44 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 45 | - "SPICEDB_DATASTORE_ENGINE=cockroachdb" 46 | - "SPICEDB_DATASTORE_CONN_URI=postgresql://root:secret@crdb:26257/spicedb?sslmode=disable" 47 | - "SPICEDB_LOG_LEVEL=info" 48 | - "SPICEDB_LOG_FORMAT=console" 49 | depends_on: 50 | - "migrate" 51 | 52 | migrate: 53 | image: "authzed/spicedb" 54 | command: "migrate head" 55 | restart: "on-failure:3" 56 | environment: 57 | - "SPICEDB_DATASTORE_ENGINE=cockroachdb" 58 | - "SPICEDB_DATASTORE_CONN_URI=postgresql://root:secret@crdb:26257/spicedb?sslmode=disable" 59 | - "SPICEDB_LOG_LEVEL=info" 60 | - "SPICEDB_LOG_FORMAT=console" 61 | depends_on: 62 | - "init_database" 63 | 64 | init_database: 65 | image: "cockroachdb/cockroach" 66 | restart: "on-failure:3" 67 | command: "sql --insecure -e 'CREATE DATABASE IF NOT EXISTS spicedb;'" 68 | environment: 69 | - "COCKROACH_HOST=crdb:26257" 70 | depends_on: 71 | - "init_cluster" 72 | 73 | enable_changefeeds: 74 | image: "cockroachdb/cockroach" 75 | restart: "on-failure:3" 76 | command: "sql --insecure -e 'SET CLUSTER SETTING kv.rangefeed.enabled = true;'" 77 | environment: 78 | - "COCKROACH_HOST=crdb:26257" 79 | depends_on: 80 | - "init_database" 81 | 82 | init_cluster: 83 | image: "cockroachdb/cockroach" 84 | restart: "on-failure:3" 85 | command: "init --insecure" 86 | environment: 87 | # initialize cluster through node 1 88 | - "COCKROACH_HOST=datastores-crdb-1:26257" 89 | depends_on: 90 | - "crdb" 91 | 92 | crdb: 93 | image: "cockroachdb/cockroach" 94 | # in order to make the cluster form, the host name is -- 95 | # The setup will support --scale arg with any value 96 | command: "start --join=datastores-crdb-1,datastores-crdb-2,datastores-crdb-3 --insecure" 97 | ports: 98 | - "8080" 99 | - "26257" 100 | environment: 101 | - "POSTGRES_PASSWORD=secret" 102 | healthcheck: 103 | test: "curl --fail http://localhost:8080/health?ready=1 || exit 1" 104 | interval: "2s" 105 | retries: 3 106 | start_period: "15s" 107 | timeout: "5s" 108 | -------------------------------------------------------------------------------- /datastores/memory.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This runs SpiceDB, using an in-memory datastore as a the storage engine. 3 | # SpiceDB will not have any schema written to it. 4 | # 5 | # SpiceDB settings: 6 | # pre-shared key: foobar 7 | # dashboard address: http://localhost:8080 8 | # metrics address: http://localhost:9090 9 | # grpc address: http://localhost:50051 10 | 11 | version: "3" 12 | 13 | services: 14 | spicedb: 15 | image: "authzed/spicedb" 16 | command: "serve" 17 | restart: "always" 18 | ports: 19 | - "8080:8080" 20 | - "9090:9090" 21 | - "50051:50051" 22 | environment: 23 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 24 | - "SPICEDB_DATASTORE_ENGINE=memory" 25 | -------------------------------------------------------------------------------- /datastores/mysql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This runs SpiceDB, using MySQL as the storage engine. SpiceDB will not have 3 | # any schema written to it. 4 | # 5 | # Once the database service is running, the migrate service executes, running 6 | # "spicedb migrate head" to migrate MySQL to the most current revision. After 7 | # MySQL is migrated, the migrate service will stop. 8 | # 9 | # SpiceDB settings: 10 | # pre-shared key: foobar 11 | # dashboard address: http://localhost:8080 12 | # metrics address: http://localhost:9090 13 | # grpc address: http://localhost:50051 14 | # 15 | # MySQL settings: 16 | # user: root 17 | # password: secret 18 | # port: 3306 19 | 20 | version: "3" 21 | 22 | services: 23 | spicedb: 24 | image: "authzed/spicedb" 25 | command: "serve" 26 | restart: "always" 27 | ports: 28 | - "8080:8080" 29 | - "9090:9090" 30 | - "50051:50051" 31 | environment: 32 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 33 | - "SPICEDB_DATASTORE_ENGINE=mysql" 34 | - "SPICEDB_DATASTORE_CONN_URI=root:secret@tcp(database:3306)/spicedb?parseTime=true" 35 | depends_on: 36 | - "migrate" 37 | 38 | migrate: 39 | image: "authzed/spicedb" 40 | command: "migrate head" 41 | restart: "on-failure" 42 | environment: 43 | - "SPICEDB_DATASTORE_ENGINE=mysql" 44 | - "SPICEDB_DATASTORE_CONN_URI=root:secret@tcp(database:3306)/spicedb?parseTime=true" 45 | depends_on: 46 | - "database" 47 | 48 | database: 49 | image: "mysql" 50 | ports: 51 | - "3306:3306" 52 | environment: 53 | - "MYSQL_ROOT_PASSWORD=secret" 54 | - "MYSQL_DATABASE=spicedb" 55 | -------------------------------------------------------------------------------- /datastores/postgres.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This runs SpiceDB, using Postgres as the storage engine. SpiceDB will not have 3 | # any schema written to it. 4 | # 5 | # Once the database service is running, the migrate service executes, running 6 | # "spicedb migrate head" to migrate Postgres to the most current revision. After 7 | # Postgres is migrated, the migrate service will stop. 8 | # 9 | # SpiceDB settings: 10 | # pre-shared key: foobar 11 | # metrics address: http://localhost:9090 12 | # grpc address: localhost:50051 13 | # 14 | # Postgres settings: 15 | # user: postgres 16 | # password: secret 17 | # port: 5432 18 | # 19 | # example call with zed: 20 | # zed schema read --endpoint=localhost:50051 --insecure=true 21 | 22 | version: "3" 23 | 24 | services: 25 | spicedb: 26 | image: "authzed/spicedb" 27 | command: "serve" 28 | restart: "always" 29 | ports: 30 | - "8080:8080" 31 | - "9090:9090" 32 | - "50051:50051" 33 | environment: 34 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 35 | - "SPICEDB_DATASTORE_ENGINE=postgres" 36 | - "SPICEDB_DATASTORE_CONN_URI=postgres://postgres:secret@database:5432/spicedb?sslmode=disable" 37 | depends_on: 38 | - "migrate" 39 | 40 | migrate: 41 | image: "authzed/spicedb" 42 | command: "migrate head" 43 | restart: "on-failure" 44 | environment: 45 | - "SPICEDB_DATASTORE_ENGINE=postgres" 46 | - "SPICEDB_DATASTORE_CONN_URI=postgres://postgres:secret@database:5432/spicedb?sslmode=disable" 47 | depends_on: 48 | - "database" 49 | 50 | database: 51 | image: "postgres:15" 52 | ports: 53 | - "5432:5432" 54 | environment: 55 | - "POSTGRES_PASSWORD=secret" 56 | - "POSTGRES_DB=spicedb" 57 | 58 | # track_commit_timestamp is required to support SpiceDB's Watch API 59 | # see https://authzed.com/docs/spicedb/concepts/datastores#usage-notes-2 60 | init_database: 61 | image: "postgres:15" 62 | restart: "on-failure:3" 63 | command: "psql -h database -U postgres -c \"ALTER SYSTEM SET track_commit_timestamp = on;\"" 64 | environment: 65 | - "PGPASSWORD=secret" 66 | depends_on: 67 | - "database" 68 | -------------------------------------------------------------------------------- /datastores/spanner.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This runs SpiceDB, using Spanner as the storage engine. SpiceDB will not have 3 | # any schema written to it. 4 | # 5 | # In order to run Spanner locally, a Spanner emulator must be spun up. This is 6 | # done by the database service. Once that is complete, the emulator must be 7 | # initialized with a project, instance, and database. This is accomplished by 8 | # the init_database service, which executes the init script found at 9 | # spanner/spanner-init. This script configures the Spanner emulator with the a 10 | # project, instance, and database. Finally, the migrate service executes, 11 | # running "spicedb migrate head" to migrate Spanner to the most current 12 | # revision. After Spanner is initialized and migrated, the init_database and 13 | # migrate services will stop. 14 | # 15 | # Note: Spanner is run using a single node configuration. 16 | # 17 | # SpiceDB settings: 18 | # pre-shared key: foobar 19 | # dashboard address: http://localhost:8080 20 | # metrics address: http://localhost:9090 21 | # grpc address: http://localhost:50051 22 | # 23 | # Spanner settings: 24 | # project id: project-spicedb 25 | # instance name: instance-spicedb 26 | # database name: spicedb 27 | # grpc port: 9010 28 | # http port: 9020 29 | 30 | version: "3" 31 | 32 | services: 33 | spicedb: 34 | image: "authzed/spicedb" 35 | command: "serve" 36 | restart: "always" 37 | ports: 38 | - "8080:8080" 39 | - "9090:9090" 40 | - "50051:50051" 41 | environment: 42 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 43 | - "SPICEDB_DATASTORE_ENGINE=spanner" 44 | - "SPICEDB_DATASTORE_CONN_URI=projects/project-spicedb/instances/instance-spicedb/databases/spicedb" 45 | - "SPANNER_EMULATOR_HOST=database:9010" 46 | depends_on: 47 | - "migrate" 48 | 49 | migrate: 50 | image: "authzed/spicedb" 51 | command: "migrate head" 52 | restart: "on-failure" 53 | environment: 54 | - "SPICEDB_DATASTORE_ENGINE=spanner" 55 | - "SPICEDB_DATASTORE_CONN_URI=projects/project-spicedb/instances/instance-spicedb/databases/spicedb" 56 | - "SPANNER_EMULATOR_HOST=database:9010" 57 | depends_on: 58 | - "database_init" 59 | 60 | database_init: 61 | build: 62 | context: "./spanner" 63 | dockerfile: "Dockerfile.spanner" 64 | restart: "on-failure" 65 | environment: 66 | - "EMULATOR_HOST=http://database:9020/" 67 | - "INSTANCE_NAME=instance-spicedb" 68 | - "PROJECT_ID=project-spicedb" 69 | depends_on: 70 | - "database" 71 | 72 | database: 73 | image: "gcr.io/cloud-spanner-emulator/emulator" 74 | ports: 75 | - "9010:9010" 76 | - "9020:9020" 77 | -------------------------------------------------------------------------------- /datastores/spanner/Dockerfile.spanner: -------------------------------------------------------------------------------- 1 | FROM google/cloud-sdk:slim 2 | 3 | RUN apt-get install -y google-cloud-sdk 4 | 5 | ENV EMULATOR_HOST="" 6 | ENV INSTANCE_NAME="" 7 | ENV PROJECT_ID="" 8 | 9 | COPY spanner-init . 10 | 11 | CMD ./spanner-init 12 | -------------------------------------------------------------------------------- /datastores/spanner/spanner-init: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #/ Sets up a spanner instance for SpiceDB. 3 | #/ 4 | #/ Expects the following environment variables: 5 | #/ EMULATOR_HOST Host of the the Spanner emulator (i.e. http://localhost:9020/) 6 | #/ WARN: This must have a trailing / 7 | #/ INSTANCE_NAME Name of the Spanner instance 8 | #/ PROJECT_ID Name of the project id 9 | 10 | # configure gcloud cli to connect to emulator 11 | gcloud config set auth/disable_credentials true 12 | gcloud config set project $PROJECT_ID 13 | gcloud config set api_endpoint_overrides/spanner $EMULATOR_HOST 14 | 15 | # create spanner instance 16 | gcloud spanner instances create $INSTANCE_NAME \ 17 | --config=emulator-config \ 18 | --description="Test Instance" \ 19 | --nodes=1 20 | 21 | gcloud config set spanner/instance $INSTANCE_NAME 22 | 23 | # create database 24 | gcloud spanner databases create spicedb 25 | -------------------------------------------------------------------------------- /github-actions/README.md: -------------------------------------------------------------------------------- 1 | # SpiceDB GitHub Actions Examples 2 | 3 | The files in this directory provide examples for [GitHub Actions] users. 4 | 5 | [GitHub Actions]: https://github.com/features/actions 6 | 7 | There are two official Actions: 8 | 9 | - [authzed/action-spicedb](https://github.com/authzed/action-spicedb) for integration testing your application with SpiceDB 10 | - [authzed/action-spicedb-validate](https://github.com/authzed/action-spicedb-validate) for validating your SpiceDB schema 11 | 12 | -------------------------------------------------------------------------------- /github-actions/integration-tests.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Example Integration Tests" 3 | on: # yamllint disable-line rule:truthy 4 | - "push" 5 | - "pull_request" 6 | jobs: 7 | integration: 8 | runs-on: "ubuntu-latest" 9 | steps: 10 | - uses: "actions/checkout@v3" 11 | - uses: "authzed/action-spicedb@v1" 12 | with: 13 | version: "latest" # Update this to be a stable release version! 14 | -------------------------------------------------------------------------------- /github-actions/validate-schema.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Example Schema Validate" 3 | on: # yamllint disable-line rule:truthy 4 | - "push" 5 | - "pull_request" 6 | jobs: 7 | test: 8 | runs-on: "ubuntu-latest" 9 | steps: 10 | - uses: "actions/checkout@v3" 11 | - uses: "authzed/action-spicedb-validate@v1" 12 | with: 13 | validationfile: "myschema.zed" # Update this to be your schema file! 14 | -------------------------------------------------------------------------------- /integration-testing/README.md: -------------------------------------------------------------------------------- 1 | # Integration Testing against SpiceDB 2 | 3 | This demonstrates how to perform integration tests against SpiceDB. 4 | 5 | Even if you are not using Go, the fundamentals should remain the same: 6 | 7 | 1. Spin up a SpiceDB container running the `serve-testing` command. 8 | 2. For each independent test, create a SpiceDB client with a random key. 9 | 3. Run tests. Tests with different keys are safe to run in parallel. 10 | -------------------------------------------------------------------------------- /integration-testing/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/authzed/examples/integration-testing 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/authzed/authzed-go v0.6.0 7 | github.com/authzed/grpcutil v0.0.0-20220104222419-f813f77722e5 8 | github.com/ory/dockertest/v3 v3.9.1 9 | google.golang.org/grpc v1.48.0 10 | ) 11 | 12 | require ( 13 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect 14 | github.com/Microsoft/go-winio v0.5.2 // indirect 15 | github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect 16 | github.com/cenkalti/backoff/v4 v4.1.3 // indirect 17 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect 18 | github.com/containerd/continuity v0.3.0 // indirect 19 | github.com/davecgh/go-spew v1.1.1 // indirect 20 | github.com/docker/cli v20.10.14+incompatible // indirect 21 | github.com/docker/docker v20.10.7+incompatible // indirect 22 | github.com/docker/go-connections v0.4.0 // indirect 23 | github.com/docker/go-units v0.4.0 // indirect 24 | github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect 25 | github.com/gogo/protobuf v1.3.2 // indirect 26 | github.com/golang/protobuf v1.5.2 // indirect 27 | github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect 28 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect 29 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 // indirect 30 | github.com/imdario/mergo v0.3.12 // indirect 31 | github.com/jzelinskie/stringz v0.0.0-20210414224931-d6a8ce844a70 // indirect 32 | github.com/mitchellh/mapstructure v1.4.1 // indirect 33 | github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect 34 | github.com/opencontainers/go-digest v1.0.0 // indirect 35 | github.com/opencontainers/image-spec v1.0.2 // indirect 36 | github.com/opencontainers/runc v1.1.2 // indirect 37 | github.com/pkg/errors v0.9.1 // indirect 38 | github.com/pmezard/go-difflib v1.0.0 // indirect 39 | github.com/sirupsen/logrus v1.8.1 // indirect 40 | github.com/stretchr/testify v1.7.1 // indirect 41 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect 42 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect 43 | github.com/xeipuuv/gojsonschema v1.2.0 // indirect 44 | golang.org/x/net v0.0.0-20210913180222-943fd674d43e // indirect 45 | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect 46 | golang.org/x/text v0.3.7 // indirect 47 | google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af // indirect 48 | google.golang.org/protobuf v1.27.1 // indirect 49 | gopkg.in/yaml.v2 v2.3.0 // indirect 50 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 51 | ) 52 | -------------------------------------------------------------------------------- /integration-testing/main_test.go: -------------------------------------------------------------------------------- 1 | // This demonstrates how to perform integration tests against SpiceDB. 2 | // 3 | // Even if you are not using Go, the fundamentals should remain the same: 4 | // 1. Spin up a SpiceDB container running the `serve-testing` command. 5 | // 2. For each independent test, create a SpiceDB client with a random key. 6 | // 3. Run tests. Tests with different keys are safe to run in parallel. 7 | package main 8 | 9 | import ( 10 | "context" 11 | "crypto/rand" 12 | "encoding/base64" 13 | "testing" 14 | 15 | v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 16 | "github.com/authzed/authzed-go/v1" 17 | "github.com/authzed/grpcutil" 18 | "github.com/ory/dockertest/v3" 19 | "google.golang.org/grpc" 20 | "google.golang.org/grpc/credentials/insecure" 21 | ) 22 | 23 | // runSpiceDBTestServer spins up a SpiceDB container running the integration 24 | // test server. 25 | func runSpiceDBTestServer(t *testing.T) (port string, err error) { 26 | pool, err := dockertest.NewPool("") // Empty string uses default docker env 27 | if err != nil { 28 | return 29 | } 30 | 31 | resource, err := pool.RunWithOptions(&dockertest.RunOptions{ 32 | Repository: "authzed/spicedb", 33 | Tag: "latest", // Replace this with an actual version 34 | Cmd: []string{"serve-testing"}, 35 | ExposedPorts: []string{"50051/tcp", "50052/tcp"}, 36 | }) 37 | if err != nil { 38 | return 39 | } 40 | 41 | // When you're done, kill and remove the container 42 | t.Cleanup(func() { 43 | _ = pool.Purge(resource) 44 | }) 45 | 46 | return resource.GetPort("50051/tcp"), nil 47 | } 48 | 49 | // spicedbTestClient creates a new SpiceDB client with random credentials. 50 | // 51 | // The test server gives each set of a credentials its own isolated datastore 52 | // so that tests can be ran in parallel. 53 | func spicedbTestClient(t *testing.T, port string) (*authzed.Client, error) { 54 | // Generate a random credential to isolate this client from any others. 55 | buf := make([]byte, 20) 56 | if _, err := rand.Read(buf); err != nil { 57 | return nil, err 58 | } 59 | randomKey := base64.StdEncoding.EncodeToString(buf) 60 | 61 | return authzed.NewClient( 62 | "localhost:"+port, 63 | grpc.WithTransportCredentials(insecure.NewCredentials()), 64 | grpcutil.WithInsecureBearerToken(randomKey), 65 | grpc.WithBlock(), 66 | ) 67 | } 68 | 69 | func TestSpiceDB(t *testing.T) { 70 | port, err := runSpiceDBTestServer(t) 71 | if err != nil { 72 | t.Fatal(err) 73 | } 74 | 75 | tests := []struct { 76 | name string 77 | schema string 78 | }{ 79 | { 80 | "basic readback", 81 | `definition user {}`, 82 | }, 83 | } 84 | 85 | for _, tt := range tests { 86 | t.Run(tt.name, func(t *testing.T) { 87 | t.Parallel() 88 | 89 | client, err := spicedbTestClient(t, port) 90 | if err != nil { 91 | t.Fatal(err) 92 | } 93 | 94 | _, err = client.WriteSchema(context.TODO(), &v1.WriteSchemaRequest{Schema: tt.schema}) 95 | if err != nil { 96 | t.Fatal(err) 97 | } 98 | 99 | resp, err := client.ReadSchema(context.TODO(), &v1.ReadSchemaRequest{}) 100 | if err != nil { 101 | t.Fatal(err) 102 | } 103 | 104 | if tt.schema != resp.SchemaText { 105 | t.Fatal(err) 106 | } 107 | }) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /kubernetes/example.yaml: -------------------------------------------------------------------------------- 1 | # This file contains an example configuration of SpiceDB in Kubernetes. 2 | # 3 | # This configuration is not an accurate representation of a production 4 | # deployment or an ideal candidate for benchmarking performance. 5 | # 6 | # It creates the following: 7 | # - A single node deployment with no persistence (in-memory datastore) 8 | # - Ports for the gRPC and HTTP APIs 9 | # - Ports for internal dispatching and metrics 10 | # - TLS is NOT securing any connections 11 | # - Logging configured at the debug log-level 12 | # 13 | # To apply this configuration execute the following: 14 | # kubectl -n $YOUR_NAMESPACE create secret generic spicedb --from-literal=SPICEDB_GRPC_PRESHARED_KEY=$YOUR_SECRET 15 | # kubectl -n $YOUR_NAMESPACE create -f example.yaml 16 | --- 17 | apiVersion: "v1" 18 | kind: "Service" 19 | metadata: 20 | name: "spicedb" 21 | labels: 22 | app.kubernetes.io/name: "spicedb" 23 | app.kubernetes.io/version: "example" 24 | annotations: 25 | prometheus.io/scrape: "true" 26 | prometheus.io/port: "9090" 27 | spec: 28 | selector: 29 | app: "spicedb" 30 | type: "ClusterIP" 31 | ports: 32 | - name: "grpc" 33 | port: 50051 34 | protocol: "TCP" 35 | targetPort: 50051 36 | - name: "http" 37 | port: 8443 38 | protocol: "TCP" 39 | targetPort: 8443 40 | - name: "dispatch" 41 | port: 50053 42 | protocol: "TCP" 43 | targetPort: 50053 44 | - name: "prometheus" 45 | port: 9090 46 | protocol: "TCP" 47 | targetPort: 9090 48 | --- 49 | apiVersion: "apps/v1" 50 | kind: "Deployment" 51 | metadata: 52 | name: "spicedb" 53 | labels: 54 | app.kubernetes.io/name: "spicedb" 55 | app.kubernetes.io/version: "example" 56 | spec: 57 | replicas: 1 58 | selector: 59 | matchLabels: 60 | app.kubernetes.io/name: "spicedb" 61 | app.kubernetes.io/version: "example" 62 | strategy: 63 | type: "RollingUpdate" 64 | rollingUpdate: 65 | maxSurge: "25%" 66 | maxUnavailable: "25%" 67 | progressDeadlineSeconds: 600 68 | template: 69 | metadata: 70 | labels: 71 | app.kubernetes.io/name: "spicedb" 72 | app.kubernetes.io/version: "example" 73 | spec: 74 | dnsPolicy: "ClusterFirst" 75 | restartPolicy: "Always" 76 | terminationGracePeriodSeconds: 30 77 | serviceAccountName: "spicedb" 78 | containers: 79 | - name: "spicedb" 80 | image: "quay.io/authzed/spicedb:latest" 81 | imagePullPolicy: "Always" 82 | command: ["spicedb", "serve"] 83 | env: 84 | # These flags are used to enable TLS for the gRPC and HTTP ports: 85 | # 86 | # - name: "SPICEDB_GRPC_TLS_KEY_PATH" 87 | # valueFrom: 88 | # secretKeyRef: 89 | # name: "spicedb" 90 | # key: "SPICEDB_GRPC_KEY_PATH" 91 | # - name: "SPICEDB_GRPC_TLS_CERT_PATH" 92 | # valueFrom: 93 | # secretKeyRef: 94 | # name: "spicedb" 95 | # key: "SPICEDB_GRPC_CERT_PATH" 96 | # - name: "SPICEDB_HTTP_TLS_KEY_PATH" 97 | # valueFrom: 98 | # secretKeyRef: 99 | # name: "spicedb" 100 | # key: "SPICEDB_HTTP_KEY_PATH" 101 | # - name: "SPICEDB_HTTP_TLS_CERT_PATH" 102 | # valueFrom: 103 | # secretKeyRef: 104 | # name: "spicedb" 105 | # key: "SPICEDB_HTTP_TLS_CERT_PATH" 106 | # 107 | # These flags are used to enable a persistent datastore along 108 | # with cluster dispatching. For more info see: 109 | # https://docs.authzed.com/spicedb/selecting-a-datastore 110 | # 111 | # - name: "SPICEDB_DATASTORE_ENGINE" 112 | # value: "cockroachdb" 113 | # - name: "SPICEDB_DATASTORE_CONN_URI" 114 | # valueFrom: 115 | # secretKeyRef: 116 | # name: "spicedb" 117 | # key: "SPICEDB_DATASTORE_CONN_URI" 118 | # - name: "SPICEDB_DISPATCH_CLUSTER_ENABLED" 119 | # value: "true" 120 | # - name: "SPICEDB_DISPATCH_UPSTREAM_ADDR" 121 | # value: "kubernetes:///spicedb:dispatch" 122 | - name: "SPICEDB_LOG_LEVEL" 123 | value: "debug" 124 | - name: "SPICEDB_HTTP_ENABLED" 125 | value: "true" 126 | - name: "SPICEDB_GRPC_SHUTDOWN_GRACE_PERIOD" 127 | value: "1s" 128 | - name: "SPICEDB_GRPC_PRESHARED_KEY" 129 | valueFrom: 130 | secretKeyRef: 131 | name: "spicedb" 132 | key: "SPICEDB_GRPC_PRESHARED_KEY" 133 | ports: 134 | - name: "grpc" 135 | containerPort: 50051 136 | protocol: "TCP" 137 | - name: "http" 138 | containerPort: 8443 139 | protocol: "TCP" 140 | - name: "dispatch" 141 | containerPort: 50053 142 | protocol: "TCP" 143 | - name: "prometheus" 144 | containerPort: 9090 145 | protocol: "TCP" 146 | readinessProbe: 147 | exec: 148 | command: ["grpc_health_probe", "-v", "-addr=localhost:50051"] 149 | failureThreshold: 5 150 | periodSeconds: 10 151 | successThreshold: 1 152 | timeoutSeconds: 5 153 | --- 154 | apiVersion: "v1" 155 | kind: "ServiceAccount" 156 | metadata: 157 | name: "spicedb" 158 | labels: 159 | app.kubernetes.io/name: "spicedb" 160 | app.kubernetes.io/version: "example" 161 | --- 162 | apiVersion: "rbac.authorization.k8s.io/v1" 163 | kind: "Role" 164 | metadata: 165 | name: "watch-service" 166 | labels: 167 | app.kubernetes.io/name: "spicedb" 168 | app.kubernetes.io/version: "example" 169 | rules: 170 | - apiGroups: [""] 171 | resources: ["endpoints"] 172 | verbs: ["get", "watch"] 173 | --- 174 | apiVersion: "rbac.authorization.k8s.io/v1" 175 | kind: "RoleBinding" 176 | metadata: 177 | name: "spicedb-watch-service" 178 | labels: 179 | app.kubernetes.io/name: "spicedb" 180 | app.kubernetes.io/version: "example" 181 | subjects: 182 | - kind: "ServiceAccount" 183 | name: "spicedb" 184 | roleRef: 185 | apiGroup: "rbac.authorization.k8s.io" 186 | kind: "Role" 187 | name: "watch-service" 188 | -------------------------------------------------------------------------------- /notebooks/rag/requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.5 2 | aiosignal==1.3.2 3 | annotated-types==0.7.0 4 | anyio==4.8.0 5 | appnope==0.1.4 6 | asttokens==3.0.0 7 | attrs==24.3.0 8 | authzed==1.1.0 9 | certifi==2024.12.14 10 | charset-normalizer==3.4.1 11 | comm==0.2.2 12 | debugpy==1.8.11 13 | decorator==5.1.1 14 | distro==1.9.0 15 | executing==2.1.0 16 | frozenlist==1.5.0 17 | googleapis-common-protos==1.66.0 18 | grpc-interceptor==0.15.4 19 | grpcio==1.69.0 20 | h11==0.14.0 21 | httpcore==1.0.7 22 | httpx==0.28.1 23 | idna==3.10 24 | iniconfig==2.0.0 25 | ipykernel==6.29.5 26 | ipython==8.31.0 27 | jedi==0.19.2 28 | jiter==0.8.2 29 | jsonpatch==1.33 30 | jsonpointer==3.0.0 31 | jupyter_client==8.6.3 32 | jupyter_core==5.7.2 33 | langchain==0.3.14 34 | langchain-core==0.3.29 35 | langchain-openai==0.2.14 36 | langchain-pinecone==0.2.1 37 | langchain-tests==0.3.7 38 | langchain-text-splitters==0.3.5 39 | langsmith==0.2.10 40 | matplotlib-inline==0.1.7 41 | multidict==6.1.0 42 | nest-asyncio==1.6.0 43 | numpy==1.26.4 44 | openai==1.59.4 45 | orjson==3.10.13 46 | packaging==24.2 47 | parso==0.8.4 48 | pexpect==4.9.0 49 | pinecone==5.4.2 50 | pinecone-plugin-inference==3.1.0 51 | pinecone-plugin-interface==0.0.7 52 | platformdirs==4.3.6 53 | pluggy==1.5.0 54 | prompt_toolkit==3.0.48 55 | propcache==0.2.1 56 | protobuf==5.29.2 57 | psutil==6.1.1 58 | ptyprocess==0.7.0 59 | pure_eval==0.2.3 60 | pydantic==2.10.4 61 | pydantic_core==2.27.2 62 | Pygments==2.19.1 63 | pytest==8.3.4 64 | pytest-asyncio==0.25.1 65 | pytest-socket==0.7.0 66 | python-dateutil==2.9.0.post0 67 | python-dotenv==1.0.1 68 | PyYAML==6.0.2 69 | pyzmq==26.2.0 70 | regex==2024.11.6 71 | requests==2.32.3 72 | requests-toolbelt==1.0.0 73 | six==1.17.0 74 | sniffio==1.3.1 75 | SQLAlchemy==2.0.36 76 | stack-data==0.6.3 77 | syrupy==4.8.0 78 | tenacity==9.0.0 79 | tiktoken==0.8.0 80 | tornado==6.4.2 81 | tqdm==4.67.1 82 | traitlets==5.14.3 83 | typing_extensions==4.12.2 84 | urllib3==2.3.0 85 | wcwidth==0.2.13 86 | yarl==1.18.3 -------------------------------------------------------------------------------- /observability/simple-datadog/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /observability/simple-datadog/README.md: -------------------------------------------------------------------------------- 1 | # Spicedb Observability with the Datadog Agent 2 | 3 | ## Overview 4 | This is a repository that demonstrates a configuration of SpiceDB and the Datadog Agent 5 | that supports sending metrics and traces to Datadog. This is not the only valid configuration 6 | and should be adapted to your use case. 7 | 8 | The metrics produced in this configuration are submitted as custom metrics. We're actively working 9 | on an official SpiceDB integration that would make the metrics into standard metrics and simplify 10 | setup and configuration. 11 | 12 | ### Running in Production 13 | A "real" deployment would use a container runtime of some sort. One approach would be to 14 | run the datadog agent as a sidecar; another would be to run a set of agents using 15 | the [Datadog Operator](https://docs.datadoghq.com/getting_started/containers/datadog_operator/) 16 | and then point them at your SpiceDB instances using [annotations](https://docs.datadoghq.com/containers/kubernetes/integrations). 17 | This repository is only intended to communicate the agent check configuration 18 | and the required SpiceDB configuration. 19 | 20 | ## Running this repo 21 | ``` 22 | mv placeholder.env .env 23 | ``` 24 | 25 | Define your `DD_API_KEY` in the env file. 26 | 27 | Run `docker compose up`. 28 | 29 | ### Thumper 30 | This is an internal load-testing tool that we built a while back. We use it in this project to 31 | exercise gRPC endpoints so that there are traces and metrics to look at. 32 | 33 | ## The Dashboard 34 | This is a preview of the dashboard that will be bundled with the SpiceDB Community integration. 35 | It shows throughput, latency, and some basic node CPU and memory metrics. Note that the CPU and memory 36 | metrics may be missing context from the container runtime environment, such as limits provided by kubernetes. 37 | 38 | Also note that the dashboard uses the metrics exported by SpiceDB as histogram metrics, which Datadog then internally 39 | converts to its distribution-style metrics. There's likely some loss in resolution as a result; if this is a concern, 40 | and 100% of traces are being collected, it may make more sense to make the latency graphs reference the trace 41 | distribution supplied by Datadog. 42 | 43 | To use the dashboard, grab `spicedb-dashboard.json` and import it into Datadog. 44 | 45 | ## Tracing 46 | SpiceDB supports OTLP export of traces. This is configured in the environment variables in `docker-compose.yml` on 47 | the `datadog` and `spicedb` services. Traces are pushed by SpiceDB to the Datadog agent via its OTLP endpoint, 48 | and then the agent forwards them to Datadog. 49 | 50 | ## Metrics 51 | SpiceDB exposes a Prometheus metrics endpoint on port 9090 by default. This can be scraped by the Datadog Agent 52 | using its Openmetrics integration, which is compatible with the Prometheus metrics format. The configuration is 53 | visible in `conf.d/openmetrics.d/conf.yaml`. 54 | 55 | ## Logs 56 | SpiceDB writes structured JSON logs to stdout, which can be collected through your normal log collection mechanisms. 57 | 58 | ### All Available Metrics 59 | The configuration in `conf.d/openmetrics.d/conf.yaml` currently only includes those metrics required to drive the dashboard. 60 | If additional metrics are desired, their names and descriptions can be found in `all_metrics.txt`. 61 | -------------------------------------------------------------------------------- /observability/simple-datadog/conf.d/openmetrics.d/conf.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | init_config: 3 | service: "spicedb" 4 | 5 | instances: 6 | - openmetrics_endpoint: "http://spicedb:9090/metrics" 7 | # Prefixes all of the metrics scraped by DD with `spicedb.` 8 | namespace: "spicedb" 9 | metrics: 10 | - grpc_server_handling_seconds: 11 | name: "grpc.server.handling" 12 | type: "histogram" 13 | - grpc_server_handled: 14 | name: "grpc.server.handled" 15 | type: "counter" 16 | # NOTE: for counter metrics that are suffixed by _total, you need to 17 | # remove the suffix for Datadog to pick it up correctly. 18 | - process_cpu_seconds: 19 | name: "process.cpu.seconds" 20 | type: "counter" 21 | - process_virtual_memory_bytes: 22 | name: "process.virtual_memory_bytes" 23 | type: "gauge" 24 | histogram_buckets_as_distributions: true 25 | min_collection_interval: 5 26 | -------------------------------------------------------------------------------- /observability/simple-datadog/datadog.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # We also don't care about logs 3 | process_config: 4 | container_collection: 5 | enabled: false 6 | -------------------------------------------------------------------------------- /observability/simple-datadog/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "metrics-adventure" 3 | 4 | services: 5 | datadog: 6 | image: "datadog/agent" 7 | environment: 8 | DD_API_KEY: "${DD_API_KEY}" 9 | DD_HOSTNAME: "yetibox" 10 | 11 | # NOTE: you can't set this via the config; it needs to come from environment variables. 12 | # These are the environment variables that enable collection via OTLP. 13 | DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_GRPC_ENDPOINT: "0.0.0.0:4317" 14 | # Tells Datadog that we want to send along traces. 15 | # Additional variables would be needed for OTLP logging and metrics 16 | # if desired. 17 | DD_OTLP_CONFIG_TRACES_ENABLED: true 18 | volumes: 19 | - "./conf.d:/conf.d" 20 | - "./datadog.yaml:/datadog.yaml" 21 | 22 | spicedb: 23 | image: "authzed/spicedb:v1.38.1" 24 | command: "serve" 25 | restart: "on-failure" 26 | environment: 27 | SPICEDB_GRPC_PRESHARED_KEY: "thisisnotasecret" 28 | SPICEDB_DATASTORE_ENGINE: &datastore_engine "postgres" 29 | SPICEDB_DATASTORE_CONN_URI: &datastore_conn_uri "postgres://postgres:secret@database:5432/spicedb?sslmode=disable" 30 | 31 | # OTLP flags; this is how traces are sent to the Datadog agent. 32 | # This matches the receiver endpoint configured on the agent. 33 | SPICEDB_OTEL_ENDPOINT: "datadog:4317" 34 | # Whether to use HTTP or HTTPS 35 | SPICEDB_OTEL_INSECURE: true 36 | # Use gRPC for submission, since the DD agent supports it. `otlphttp` 37 | # is a valid option as well. 38 | SPICEDB_OTEL_PROVIDER: "otlpgrpc" 39 | # Send all traces. This defaults to 0.01 and should be tuned for your system. 40 | SPICEDB_OTEL_SAMPLE_RATIO: 1.0 41 | ports: 42 | - "9090:9090" 43 | depends_on: 44 | - "spicedb-migrate" 45 | 46 | spicedb-migrate: 47 | image: "authzed/spicedb:v1.38.1" 48 | command: "migrate head" 49 | restart: "on-failure" 50 | environment: 51 | SPICEDB_DATASTORE_ENGINE: *datastore_engine 52 | SPICEDB_DATASTORE_CONN_URI: *datastore_conn_uri 53 | depends_on: 54 | - "database" 55 | 56 | # Load generation tooling. This is to ensure that there are metrics 57 | # and traces to look at. 58 | thumper: 59 | image: "authzed/thumper" 60 | command: "run --endpoint spicedb:50051 --token thisisnotasecret /scripts/example.yaml" 61 | depends_on: 62 | - "spicedb" 63 | - "thumper-init" 64 | # This runs the schema write for the subsequent load generation. 65 | thumper-init: 66 | image: "authzed/thumper" 67 | command: "migrate --endpoint spicedb:50051 --token thisisnotasecret /scripts/schema.yaml" 68 | # Restarting on failure should mean that the init reattempts until it succeeds 69 | restart: "on-failure" 70 | depends_on: 71 | spicedb: 72 | condition: "service_started" 73 | 74 | database: 75 | image: "postgres:16" 76 | ports: 77 | - "5432:5432" 78 | environment: 79 | - "POSTGRES_PASSWORD=secret" 80 | - "POSTGRES_DB=spicedb" 81 | # This keeps postgres's data around when you bring the system down and back up 82 | volumes: 83 | - "pgdata:/var/lib/postgresql/data" 84 | 85 | volumes: 86 | pgdata: 87 | -------------------------------------------------------------------------------- /observability/simple-datadog/placeholder.env: -------------------------------------------------------------------------------- 1 | DD_API_KEY= 2 | -------------------------------------------------------------------------------- /observability/simple-datadog/spicedb-dashboard.json: -------------------------------------------------------------------------------- 1 | {"title":"SpiceDB Overview","description":"[[suggested_dashboards]]","widgets":[{"id":512625727012637,"definition":{"title":"New group","banner_img":"","show_title":false,"type":"group","layout_type":"ordered","widgets":[{"id":790129298401198,"definition":{"type":"image","url":"https://design-authzed.vercel.app/images/Banners/SpiceDB-1600x400-Banner-Light.svg","url_dark_theme":"https://design-authzed.vercel.app/images/Banners/SpiceDB-1600x400-Banner.svg","sizing":"contain","has_background":false,"has_border":false,"vertical_align":"center","horizontal_align":"left"},"layout":{"x":0,"y":0,"width":6,"height":2}},{"id":5391176615093781,"definition":{"type":"note","content":"#### Optimize your SpiceDB integration configuration for monitoring\n\n1. Configure `cluster`, `node`, and `region` tags in your `spicedb.d/conf.yaml` file:\n\n\n ```\n instances:\n - openmetrics_endpoint: http://localhost:8080/_status/vars\n tags: [\"cluster:prod\", \"node:1\", \"region:us-east-1\"]\n - openmetrics_endpoint: http://localhost:8082/_status/vars\n tags: [\"cluster:dev\", \"node:1\", \"region:us-east-2\"]\n ```","background_color":"white","font_size":"14","text_align":"left","vertical_align":"center","show_tick":false,"tick_pos":"50%","tick_edge":"left","has_padding":true},"layout":{"x":6,"y":0,"width":6,"height":3}},{"id":8404853868782660,"definition":{"type":"note","content":"This dashboard provides a high-level view of your SpiceDB cluster, including:\n- A high-level view of request performance & latency.\n- Information about resource consumption to help aid in capacity planning.","background_color":"transparent","font_size":"14","text_align":"left","vertical_align":"center","show_tick":false,"tick_pos":"50%","tick_edge":"left","has_padding":false},"layout":{"x":0,"y":2,"width":6,"height":1}}]},"layout":{"x":0,"y":0,"width":12,"height":4}},{"id":3560130955990344,"definition":{"title":"Throughput","show_title":true,"type":"group","layout_type":"ordered","widgets":[{"id":7615141942543467,"definition":{"title":"Total by RPC","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{*}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":0,"y":0,"width":6,"height":3}},{"id":3925663272929855,"definition":{"title":"Total by Consistency","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{*}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":6,"y":0,"width":6,"height":3}},{"id":364527830066764,"definition":{"title":"Check Operations","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{grpc_method:checkpermission}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":0,"y":3,"width":6,"height":3}},{"id":2823083366205463,"definition":{"title":"Lookup Operations","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{grpc_method in (lookupsubjects ,lookupresources )} by {grpc_method}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":6,"y":3,"width":6,"height":3}},{"id":279197301579739,"definition":{"title":"Relationship Operations","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{grpc_method in (readrelationships ,writerelationships ,deleterelationships )} by {grpc_method}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":0,"y":6,"width":6,"height":3}},{"id":3380816430782344,"definition":{"title":"Schema Operations","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.grpc.server.handled.count{grpc_method in (writeschema ,readschema)} by {grpc_method}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"bars"}]},"layout":{"x":6,"y":6,"width":6,"height":3}}]},"layout":{"x":0,"y":4,"width":12,"height":10}},{"id":4793433791679627,"definition":{"title":"Latency","show_title":true,"type":"group","layout_type":"ordered","widgets":[{"id":863409587490583,"definition":{"title":"Checks","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: CheckPermission","formula":"query1"},{"alias":"p95: CheckPermission","formula":"query2"},{"alias":"p95: CheckPermission","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:checkpermission}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:checkpermission}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:checkpermission}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":0,"y":0,"width":6,"height":3}},{"id":6076165849438225,"definition":{"title":"Bulk Checks","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: CheckBulkPermission","formula":"query1"},{"alias":"p95: CheckBulkPermission","formula":"query2"},{"alias":"p99: CheckBulkPermission","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method in (checkbulkpermission, bulkcheckpermission)}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method in (checkbulkpermission, bulkcheckpermission)}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method in (checkbulkpermission, bulkcheckpermission)}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":0,"width":6,"height":3}},{"id":5409060165861238,"definition":{"title":"ReadRelationships","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: ReadRelationships","formula":"query1"},{"alias":"p95: WriteRelationships","formula":"query2"},{"alias":"p99: WriteRelationships","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:readrelationships}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:readrelationships}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:readrelationships}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":0,"y":3,"width":6,"height":3}},{"id":4680938480636664,"definition":{"title":"WriteRelationships","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: WriteRelationships","formula":"query1"},{"alias":"p95: WriteRelationships","formula":"query2"},{"alias":"p99: WriteRelationships","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:writerelationships}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:writerelationships}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:writerelationships}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":3,"width":6,"height":3}},{"id":7324769101390434,"definition":{"title":"DeleteRelationships","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: DeleteRelationships","formula":"query1"},{"alias":"p95: DeleteRelationships","formula":"query2"},{"alias":"p99: DeleteRelationships","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:deleterelationships}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:deleterelationships}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:deleterelationships}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":0,"y":6,"width":6,"height":3}},{"id":2497504251532424,"definition":{"title":"ExpandPermissionTree","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: ExpandPermissionTree","formula":"query1"},{"alias":"p95: ExpandPermissionTree","formula":"query2"},{"alias":"p99: ExpandPermissionTree","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:expandpermissiontree}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:expandpermissiontree}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:expandpermissiontree}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":6,"width":6,"height":3}},{"id":8307194191289555,"definition":{"title":"LookupResources","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: LookupResources","formula":"query1"},{"alias":"p95: LookupResources","formula":"query2"},{"alias":"p99: LookupResources","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:lookupresources}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:lookupresources}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:lookupresources}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":0,"y":9,"width":6,"height":3}},{"id":8169958283522599,"definition":{"title":"LookupSubjects","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: LookupSubjects","formula":"query1"},{"alias":"p95: LookupSubjects","formula":"query2"},{"alias":"p99: LookupSubjects","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:lookupsubjects}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:lookupsubjects}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:lookupsubjects}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":9,"width":6,"height":3}},{"id":4835192591489553,"definition":{"title":"ReadSchema","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: ReadSchema","formula":"query1"},{"alias":"p95: ReadSchema","formula":"query2"},{"alias":"p99: ReadSchema","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:readschema}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:readschema}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:readschema}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":0,"y":12,"width":6,"height":3}},{"id":1786825540718652,"definition":{"title":"WriteSchema","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"p50: WriteSchema","formula":"query1"},{"alias":"p95: WriteSchema","formula":"query2"},{"alias":"p99: WriteSchema","formula":"query3"}],"queries":[{"name":"query1","data_source":"metrics","query":"p50:spicedb.grpc.server.handling{grpc_method:writeschema}"},{"name":"query2","data_source":"metrics","query":"p95:spicedb.grpc.server.handling{grpc_method:writeschema}"},{"name":"query3","data_source":"metrics","query":"p99:spicedb.grpc.server.handling{grpc_method:writeschema}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":12,"width":6,"height":3}}]},"layout":{"x":0,"y":14,"width":12,"height":16,"is_column_break":true}},{"id":1969543100199273,"definition":{"title":"Node","show_title":true,"type":"group","layout_type":"ordered","widgets":[{"id":3363586656686623,"definition":{"title":"vCPU","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"CPU %","formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"sum:spicedb.process.cpu.seconds.count{*} by {host}.as_rate()"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}],"markers":[]},"layout":{"x":0,"y":0,"width":6,"height":3}},{"id":5592139522821831,"definition":{"title":"Memory","title_size":"16","title_align":"left","show_legend":true,"legend_layout":"auto","legend_columns":["avg","min","max","value","sum"],"type":"timeseries","requests":[{"formulas":[{"alias":"Memory Usage","formula":"query1"}],"queries":[{"name":"query1","data_source":"metrics","query":"avg:spicedb.process.virtual_memory_bytes{*} by {host}"}],"response_format":"timeseries","style":{"palette":"dog_classic","order_by":"values","line_type":"solid","line_width":"normal"},"display_type":"line"}]},"layout":{"x":6,"y":0,"width":6,"height":3}}]},"layout":{"x":0,"y":30,"width":12,"height":4}}],"template_variables":[],"layout_type":"ordered","notify_list":[],"reflow_type":"fixed"} -------------------------------------------------------------------------------- /schemas/basic-rbac/README.md: -------------------------------------------------------------------------------- 1 | # Simple Role Based Access Control 2 | 3 | Models Role Based Access Control (RBAC), where access is granted to users based on the role(s) in which they are a member. 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | /** 11 | * user represents a user that can be granted role(s) 12 | */ 13 | definition user {} 14 | 15 | /** 16 | * document represents a document protected by Authzed. 17 | */ 18 | definition document { 19 | /** 20 | * writer indicates that the user is a writer on the document. 21 | */ 22 | relation writer: user 23 | 24 | /** 25 | * reader indicates that the user is a reader on the document. 26 | */ 27 | relation reader: user 28 | 29 | /** 30 | * edit indicates that the user has permission to edit the document. 31 | */ 32 | permission edit = writer 33 | 34 | /** 35 | * view indicates that the user has permission to view the document, if they 36 | * are a `reader` *or* have `edit` permission. 37 | */ 38 | permission view = reader + edit 39 | } 40 | ``` 41 | 42 | The RBAC example defines two kinds of objects: `user` to be used as references to users and `document`, representing a resource being protected (in this case, a document). 43 | 44 | ### user 45 | 46 | `user` is an example of a "user" definition, which is used to represent users. The definition itself is empty, as it is only used for referencing purposes. 47 | 48 | ```zed 49 | definition user {} 50 | ``` 51 | 52 | ### document 53 | 54 | `document` is an example of a "resource" definition, which is used to define the relations and permissions for a specific kind of resource. Here, that resource is a document. 55 | 56 | ```zed 57 | definition document { 58 | /** 59 | * writer indicates that the user is a writer on the document. 60 | */ 61 | relation writer: user 62 | 63 | /** 64 | * reader indicates that the user is a reader on the document. 65 | */ 66 | relation reader: user 67 | 68 | /** 69 | * edit indicates that the user has permission to edit the document. 70 | */ 71 | permission edit = writer 72 | 73 | /** 74 | * view indicates that the user has permission to view the document, if they 75 | * are a `reader` *or* have `edit` permission. 76 | */ 77 | permission view = reader + edit 78 | } 79 | ``` 80 | 81 | Within the `document` definition, there are defined two relations `reader` and `writer`, which are used to represent roles for users, and two permissions `edit` and `view`, which represent the permissions that can be checked on a document. 82 | 83 | #### writer 84 | 85 | The `writer` relation defines a role of "writer" for users. 86 | 87 | #### reader 88 | 89 | The `reader` relation defines a role of "reader" for users. 90 | 91 | #### edit 92 | 93 | The `edit` permission defines an edit permission on the document. 94 | 95 | #### view 96 | 97 | The `view` permission defines a view permission on the document. 98 | 99 | Note that `view` includes the `edit` permission. This means that if a user is granted the role of `writer` and thus, has `edit` permission, they will _also_ be implicitly granted the permission of `view`. 100 | -------------------------------------------------------------------------------- /schemas/basic-rbac/schema-and-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schema: |- 3 | /** 4 | * user represents a user that can be granted role(s) 5 | */ 6 | definition user {} 7 | 8 | /** 9 | * document represents a document protected by Authzed. 10 | */ 11 | definition document { 12 | /** 13 | * writer indicates that the user is a writer on the document. 14 | */ 15 | relation writer: user 16 | 17 | /** 18 | * reader indicates that the user is a reader on the document. 19 | */ 20 | relation reader: user 21 | 22 | /** 23 | * edit indicates that the user has permission to edit the document. 24 | */ 25 | permission edit = writer 26 | 27 | /** 28 | * view indicates that the user has permission to view the document, if they 29 | * are a `reader` *or* have `edit` permission. 30 | */ 31 | permission view = reader + edit 32 | } 33 | 34 | relationships: |- 35 | document:firstdoc#writer@user:tom 36 | document:firstdoc#reader@user:fred 37 | document:seconddoc#reader@user:tom 38 | 39 | assertions: 40 | assertTrue: 41 | - "document:firstdoc#view@user:tom" 42 | - "document:firstdoc#view@user:fred" 43 | - "document:seconddoc#view@user:tom" 44 | assertFalse: 45 | - "document:seconddoc#view@user:fred" 46 | 47 | validation: 48 | document:firstdoc#view: 49 | - "[user:tom] is " 50 | - "[user:fred] is " 51 | document:seconddoc#view: 52 | - "[user:tom] is " 53 | -------------------------------------------------------------------------------- /schemas/caveats/README.md: -------------------------------------------------------------------------------- 1 | # Caveats for conditional access 2 | 3 | Models the use of caveats, which allows for conditional access based on information provided at _runtime_ to permission checks. 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | definition user {} 11 | 12 | /** 13 | * only allowed on tuesdays. `day_of_week` can be provided either at the time 14 | * the relationship is written, or in the CheckPermission API call. 15 | */ 16 | caveat only_on_tuesday(day_of_week string) { 17 | day_of_week == 'tuesday' 18 | } 19 | 20 | definition document { 21 | /** 22 | * reader indicates that the user is a reader on the document, either 23 | * directly or only on tuesday. 24 | */ 25 | relation reader: user | user with only_on_tuesday 26 | 27 | permission view = reader 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /schemas/caveats/schema-and-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schema: |- 3 | definition user {} 4 | 5 | /** 6 | * only allowed on tuesdays. `day_of_week` can be provided either at the time 7 | * the relationship is written, or in the CheckPermission API call. 8 | */ 9 | caveat only_on_tuesday(day_of_week string) { 10 | day_of_week == 'tuesday' 11 | } 12 | 13 | caveat ip_allowlist(user_ip ipaddress, cidr string) { 14 | user_ip.in_cidr(cidr) 15 | } 16 | 17 | definition document { 18 | /** 19 | * reader indicates that the user is a reader on the document, either directly, 20 | * only on tuesday, or from allowed IPs. 21 | */ 22 | relation reader: user | user with only_on_tuesday | user with ip_allowlist 23 | 24 | permission view = reader 25 | } 26 | relationships: |- 27 | document:firstdoc#reader@user:fred 28 | document:firstdoc#reader@user:tom[only_on_tuesday] 29 | document:firstdoc#reader@user:alice[ip_allowlist:{"cidr":"1.2.3.0/24"}] 30 | assertions: 31 | assertTrue: 32 | - 'document:firstdoc#view@user:tom with {"day_of_week": "tuesday"}' 33 | - "document:firstdoc#view@user:fred" 34 | - 'document:firstdoc#view@user:alice with {"user_ip": "1.2.3.4"}' 35 | assertCaveated: 36 | - "document:firstdoc#view@user:tom" 37 | - "document:firstdoc#view@user:alice" 38 | assertFalse: 39 | - 'document:firstdoc#view@user:tom with {"day_of_week": "wednesday"}' 40 | - 'document:firstdoc#view@user:alice with {"user_ip": "8.8.8.8"}' 41 | validation: 42 | document:firstdoc#view: 43 | - "[user:fred] is " 44 | - "[user:tom[...]] is " 45 | - "[user:alice[...]] is " 46 | document:seconddoc#view: [] 47 | -------------------------------------------------------------------------------- /schemas/docs-style-sharing/README.md: -------------------------------------------------------------------------------- 1 | # Google Docs-style Sharing 2 | 3 | Models a Google Docs-style sharing permission system where users can be granted direct access to a resource, or access via organizations and nested groups. 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | definition user {} 11 | 12 | definition resource { 13 | relation manager: user | usergroup#member | usergroup#manager 14 | relation viewer: user | usergroup#member | usergroup#manager 15 | 16 | permission manage = manager 17 | permission view = viewer + manager 18 | } 19 | 20 | definition usergroup { 21 | relation manager: user | usergroup#member | usergroup#manager 22 | relation direct_member: user | usergroup#member | usergroup#manager 23 | 24 | permission member = direct_member + manager 25 | } 26 | 27 | definition organization { 28 | relation group: usergroup 29 | relation administrator: user | usergroup#member | usergroup#manager 30 | relation direct_member: user 31 | 32 | relation resource: resource 33 | 34 | permission admin = administrator 35 | permission member = direct_member + administrator + group->member 36 | } 37 | ``` 38 | 39 | ### user 40 | 41 | `user` is an example of a "user" type, which is used to represent users. The definition itself is empty, as it is only used for referencing purposes. 42 | 43 | ```zed 44 | definition user {} 45 | ``` 46 | 47 | ### resource 48 | 49 | `resource` is the definition used to represent the resource being shared 50 | 51 | ```zed 52 | definition resource { 53 | relation manager: user | usergroup#member | usergroup#manager 54 | relation viewer: user | usergroup#member | usergroup#manager 55 | 56 | permission manage = manager 57 | permission view = viewer + manager 58 | } 59 | ``` 60 | 61 | Within the definition, there are defined two relations: `viewer` and `manager`, which are used to represent roles for users _or members/managers of groups_ for the resource, as well as the `view` and `manage` permissions for viewing and managing the resource, respectively. 62 | 63 | ### usergroup 64 | 65 | `usergroup` is the definition used to represent groups, which can contain either users or other groups. Groups support a distinction between member and manager. 66 | 67 | ```zed 68 | definition usergroup { 69 | relation manager: user | usergroup#member | usergroup#manager 70 | relation direct_member: user | usergroup#member | usergroup#manager 71 | 72 | permission member = direct_member + manager 73 | } 74 | ``` 75 | 76 | ### organization 77 | 78 | `organization` is the definition used to represent the overall organization. 79 | 80 | ```zed 81 | definition organization { 82 | relation group: usergroup 83 | relation administrator: user | usergroup#member | usergroup#manager 84 | relation direct_member: user 85 | 86 | relation resource: resource 87 | 88 | permission admin = administrator 89 | permission member = direct_member + administrator + group->member 90 | } 91 | ``` 92 | 93 | Organizations contain four relations (`group`, `resource`, `member`, `administrator`) which are used to reference the groups, resources, direct members and administrator users for the organization. 94 | 95 | #### member permission 96 | 97 | The `member` permission under organization computes the transitive closure of _all_ member users/groups of an organization by combining data from three sources: 98 | 99 | 1. `direct_member`: users directly added to the organization as a member 100 | 2. `administrator` is used to add any users found as an `administrator` of the organization 101 | 3. `group->member` is used to walk from the organization to any of its groups, and then from the `group` to any of its members. This ensure that if a user is available under `member` under any group in the organization, they are treated as a member of the organization as well. 102 | -------------------------------------------------------------------------------- /schemas/docs-style-sharing/schema-and-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schema: |- 3 | definition user {} 4 | 5 | definition resource { 6 | relation manager: user | usergroup#member | usergroup#manager 7 | relation viewer: user | usergroup#member | usergroup#manager 8 | 9 | permission manage = manager 10 | permission view = viewer + manager 11 | } 12 | 13 | definition usergroup { 14 | relation manager: user | usergroup#member | usergroup#manager 15 | relation direct_member: user | usergroup#member | usergroup#manager 16 | 17 | permission member = direct_member + manager 18 | } 19 | 20 | definition organization { 21 | relation group: usergroup 22 | relation administrator: user | usergroup#member | usergroup#manager 23 | relation direct_member: user 24 | 25 | relation resource: resource 26 | 27 | permission admin = administrator 28 | permission member = direct_member + administrator + group->member 29 | } 30 | 31 | relationships: |- 32 | // Add users to various groups 33 | usergroup:productname#manager@user:an_eng_manager 34 | usergroup:productname#direct_member@user:an_engineer 35 | usergroup:applications#manager@user:an_eng_director 36 | usergroup:engineering#manager@user:cto 37 | usergroup:csuite#manager@user:ceo 38 | usergroup:csuite#direct_member@user:cto 39 | 40 | // Add groups to some other groups. 41 | usergroup:engineering#direct_member@usergroup:applications#member 42 | usergroup:applications#direct_member@usergroup:productname#member 43 | usergroup:engineering#direct_member@usergroup:csuite#member 44 | 45 | // Add the groups under the organization. 46 | organization:org1#group@usergroup:csuite 47 | organization:org1#group@usergroup:productname 48 | organization:org1#group@usergroup:applications 49 | organization:org1#group@usergroup:engineering 50 | 51 | // Add some resources under the organization. 52 | organization:org1#resource@resource:promserver 53 | organization:org1#resource@resource:jira 54 | 55 | // Set a group's members and a user as the administrators of the organization. 56 | organization:org1#administrator@usergroup:csuite#member 57 | organization:org1#administrator@user:it_admin 58 | 59 | // Set the permissions on some resources. 60 | resource:promserver#manager@usergroup:productname#member 61 | resource:promserver#viewer@usergroup:engineering#member 62 | resource:jira#viewer@usergroup:engineering#member 63 | resource:jira#manager@usergroup:engineering#manager 64 | resource:promserver#viewer@user:an_external_user 65 | 66 | usergroup:blackhats#manager@user:a_villain 67 | 68 | validation: 69 | organization:org1#admin: 70 | - "[user:ceo] is " 71 | - "[user:cto] is " 72 | - "[user:it_admin] is " 73 | - "[usergroup:csuite#member] is " 74 | organization:org1#member: 75 | - "[user:an_eng_director] is " 76 | - "[user:an_eng_manager] is " 77 | - "[user:an_engineer] is " 78 | - "[user:ceo] is " 79 | - "[user:cto] is /" 80 | - "[user:it_admin] is " 81 | - "[usergroup:applications#member] is " 82 | - "[usergroup:csuite#member] is /" 83 | - "[usergroup:productname#member] is " 84 | resource:jira#manage: 85 | - "[user:cto] is " 86 | - "[usergroup:engineering#manager] is " 87 | resource:jira#view: 88 | - "[user:an_eng_director] is " 89 | - "[user:an_eng_manager] is " 90 | - "[user:an_engineer] is " 91 | - "[user:ceo] is " 92 | - "[user:cto] is /" 93 | - "[usergroup:applications#member] is " 94 | - "[usergroup:csuite#member] is " 95 | - "[usergroup:engineering#manager] is " 96 | - "[usergroup:engineering#member] is " 97 | - "[usergroup:productname#member] is " 98 | resource:promserver#manage: 99 | - "[user:an_eng_manager] is " 100 | - "[user:an_engineer] is " 101 | - "[usergroup:productname#member] is " 102 | resource:promserver#view: 103 | - "[user:an_eng_director] is " 104 | - "[user:an_eng_manager] is " 105 | - "[user:an_engineer] is " 106 | - "[user:an_external_user] is " 107 | - "[user:ceo] is " 108 | - "[user:cto] is /" 109 | - "[usergroup:applications#member] is " 110 | - "[usergroup:csuite#member] is " 111 | - "[usergroup:engineering#member] is " 112 | - "[usergroup:productname#member] is /" 113 | -------------------------------------------------------------------------------- /schemas/google-iam/README.md: -------------------------------------------------------------------------------- 1 | # Google IAM in SpiceDB 2 | 3 | Models the permissions of Google's Cloud IAM in SpiceDB. Blog post: https://authzed.com/blog/google-cloud-iam-modeling/ 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | definition user {} 11 | 12 | definition role { 13 | relation bound_user: user 14 | 15 | relation spanner_databaseoperations_cancel: role 16 | relation spanner_databaseoperations_delete: role 17 | relation spanner_databaseoperations_get: role 18 | relation spanner_databaseoperations_list: role 19 | relation spanner_databaseroles_list: role 20 | relation spanner_databaseroles_use: role 21 | relation spanner_databases_beginorrollbackreadwritetransaction: role 22 | relation spanner_databases_beginpartitioneddmltransaction: role 23 | relation spanner_databases_beginreadonlytransaction: role 24 | relation spanner_databases_create: role 25 | relation spanner_databases_drop: role 26 | relation spanner_databases_get: role 27 | relation spanner_databases_getddl: role 28 | relation spanner_databases_getiampolicy: role 29 | relation spanner_databases_list: role 30 | relation spanner_databases_partitionquery: role 31 | relation spanner_databases_partitionread: role 32 | relation spanner_databases_read: role 33 | relation spanner_databases_select: role 34 | relation spanner_databases_setiampolicy: role 35 | relation spanner_databases_update: role 36 | relation spanner_databases_updateddl: role 37 | relation spanner_databases_userolebasedaccess: role 38 | relation spanner_databases_write: role 39 | relation spanner_instances_get: role 40 | relation spanner_instances_getiampolicy: role 41 | relation spanner_instances_list: role 42 | relation spanner_sessions_create: role 43 | relation spanner_sessions_delete: role 44 | relation spanner_sessions_get: role 45 | relation spanner_sessions_list: role 46 | 47 | permission can_spanner_databaseoperations_cancel = spanner_databaseoperations_cancel->bound_user 48 | permission can_spanner_databaseoperations_delete = spanner_databaseoperations_delete->bound_user 49 | permission can_spanner_databaseoperations_get = spanner_databaseoperations_get->bound_user 50 | permission can_spanner_databaseoperations_list = spanner_databaseoperations_list->bound_user 51 | permission can_spanner_databaseroles_list = spanner_databaseroles_list->bound_user 52 | permission can_spanner_databaseroles_use = spanner_databaseroles_use->bound_user 53 | permission can_spanner_databases_beginorrollbackreadwritetransaction = spanner_databases_beginorrollbackreadwritetransaction->bound_user 54 | permission can_spanner_databases_beginpartitioneddmltransaction = spanner_databases_beginpartitioneddmltransaction->bound_user 55 | permission can_spanner_databases_beginreadonlytransaction = spanner_databases_beginreadonlytransaction->bound_user 56 | permission can_spanner_databases_create = spanner_databases_create->bound_user 57 | permission can_spanner_databases_drop = spanner_databases_drop->bound_user 58 | permission can_spanner_databases_get = spanner_databases_get->bound_user 59 | permission can_spanner_databases_getddl = spanner_databases_getddl->bound_user 60 | permission can_spanner_databases_getiampolicy = spanner_databases_getiampolicy->bound_user 61 | permission can_spanner_databases_list = spanner_databases_list->bound_user 62 | permission can_spanner_databases_partitionquery = spanner_databases_partitionquery->bound_user 63 | permission can_spanner_databases_partitionread = spanner_databases_partitionread->bound_user 64 | permission can_spanner_databases_read = spanner_databases_read->bound_user 65 | permission can_spanner_databases_select = spanner_databases_select->bound_user 66 | permission can_spanner_databases_setiampolicy = spanner_databases_setiampolicy->bound_user 67 | permission can_spanner_databases_update = spanner_databases_update->bound_user 68 | permission can_spanner_databases_updateddl = spanner_databases_updateddl->bound_user 69 | permission can_spanner_databases_userolebasedaccess = spanner_databases_userolebasedaccess->bound_user 70 | permission can_spanner_databases_write = spanner_databases_write->bound_user 71 | permission can_spanner_instances_get = spanner_instances_get->bound_user 72 | permission can_spanner_instances_getiampolicy = spanner_instances_getiampolicy->bound_user 73 | permission can_spanner_instances_list = spanner_instances_list->bound_user 74 | permission can_spanner_sessions_create = spanner_sessions_create->bound_user 75 | permission can_spanner_sessions_delete = spanner_sessions_delete->bound_user 76 | permission can_spanner_sessions_get = spanner_sessions_get->bound_user 77 | permission can_spanner_sessions_list = spanner_sessions_list->bound_user 78 | } 79 | 80 | definition project { 81 | relation granted: role 82 | 83 | // Synthetic Instance Relations 84 | permission granted_spanner_instances_get = granted->can_spanner_instances_get 85 | permission granted_spanner_instances_getiampolicy = granted->can_spanner_instances_getiampolicy 86 | permission granted_spanner_instances_list = granted->can_spanner_instances_list 87 | 88 | // Synthetic Database Relations 89 | permission granted_spanner_databases_beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction 90 | permission granted_spanner_databases_beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction 91 | permission granted_spanner_databases_beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction 92 | permission granted_spanner_databases_create = granted->can_spanner_databases_create 93 | permission granted_spanner_databases_drop = granted->can_spanner_databases_drop 94 | permission granted_spanner_databases_get = granted->can_spanner_databases_get 95 | permission granted_spanner_databases_getddl = granted->can_spanner_databases_getddl 96 | permission granted_spanner_databases_getiampolicy = granted->can_spanner_databases_getiampolicy 97 | permission granted_spanner_databases_list = granted->can_spanner_databases_list 98 | permission granted_spanner_databases_partitionquery = granted->can_spanner_databases_partitionquery 99 | permission granted_spanner_databases_partitionread = granted->can_spanner_databases_partitionread 100 | permission granted_spanner_databases_read = granted->can_spanner_databases_read 101 | permission granted_spanner_databases_select = granted->can_spanner_databases_select 102 | permission granted_spanner_databases_setiampolicy = granted->can_spanner_databases_setiampolicy 103 | permission granted_spanner_databases_update = granted->can_spanner_databases_update 104 | permission granted_spanner_databases_updateddl = granted->can_spanner_databases_updateddl 105 | permission granted_spanner_databases_userolebasedaccess = granted->can_spanner_databases_userolebasedaccess 106 | permission granted_spanner_databases_write = granted->can_spanner_databases_write 107 | 108 | // Synthetic Sessions Relations 109 | permission granted_spanner_sessions_create = granted->can_spanner_sessions_create 110 | permission granted_spanner_sessions_delete = granted->can_spanner_sessions_delete 111 | permission granted_spanner_sessions_get = granted->can_spanner_sessions_get 112 | permission granted_spanner_sessions_list = granted->can_spanner_sessions_list 113 | 114 | // Synthetic Database Operations Relations 115 | permission granted_spanner_databaseoperations_cancel = granted->can_spanner_databaseoperations_cancel 116 | permission granted_spanner_databaseoperations_delete = granted->can_spanner_databaseoperations_delete 117 | permission granted_spanner_databaseoperations_get = granted->can_spanner_databaseoperations_get 118 | permission granted_spanner_databaseoperations_list = granted->can_spanner_databaseoperations_list 119 | 120 | // Synthetic Database Roles Relations 121 | permission granted_spanner_databaseroles_list = granted->can_spanner_databaseroles_list 122 | permission granted_spanner_databaseroles_use = granted->can_spanner_databaseroles_use 123 | } 124 | 125 | definition spanner_instance { 126 | relation project: project 127 | relation granted: role 128 | 129 | permission get = granted->can_spanner_instances_get + project->granted_spanner_instances_get 130 | permission getiampolicy = granted->can_spanner_instances_getiampolicy + project->granted_spanner_instances_getiampolicy 131 | permission list = granted->can_spanner_instances_list + project->granted_spanner_instances_list 132 | 133 | // Synthetic Database Relations 134 | permission granted_spanner_databases_beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction + project->granted_spanner_databases_beginorrollbackreadwritetransaction 135 | permission granted_spanner_databases_beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction + project->granted_spanner_databases_beginpartitioneddmltransaction 136 | permission granted_spanner_databases_beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction + project->granted_spanner_databases_beginreadonlytransaction 137 | permission granted_spanner_databases_create = granted->can_spanner_databases_create + project->granted_spanner_databases_create 138 | permission granted_spanner_databases_drop = granted->can_spanner_databases_drop + project->granted_spanner_databases_drop 139 | permission granted_spanner_databases_get = granted->can_spanner_databases_get + project->granted_spanner_databases_get 140 | permission granted_spanner_databases_getddl = granted->can_spanner_databases_getddl + project->granted_spanner_databases_getddl 141 | permission granted_spanner_databases_getiampolicy = granted->can_spanner_databases_getiampolicy + project->granted_spanner_databases_getiampolicy 142 | permission granted_spanner_databases_list = granted->can_spanner_databases_list + project->granted_spanner_databases_list 143 | permission granted_spanner_databases_partitionquery = granted->can_spanner_databases_partitionquery + project->granted_spanner_databases_partitionquery 144 | permission granted_spanner_databases_partitionread = granted->can_spanner_databases_partitionread + project->granted_spanner_databases_partitionread 145 | permission granted_spanner_databases_read = granted->can_spanner_databases_read + project->granted_spanner_databases_read 146 | permission granted_spanner_databases_select = granted->can_spanner_databases_select + project->granted_spanner_databases_select 147 | permission granted_spanner_databases_setiampolicy = granted->can_spanner_databases_setiampolicy + project->granted_spanner_databases_setiampolicy 148 | permission granted_spanner_databases_update = granted->can_spanner_databases_update + project->granted_spanner_databases_update 149 | permission granted_spanner_databases_updateddl = granted->can_spanner_databases_updateddl + project->granted_spanner_databases_updateddl 150 | permission granted_spanner_databases_userolebasedaccess = granted->can_spanner_databases_userolebasedaccess + project->granted_spanner_databases_userolebasedaccess 151 | permission granted_spanner_databases_write = granted->can_spanner_databases_write + project->granted_spanner_databases_write 152 | 153 | // Synthetic Sessions Relations 154 | permission granted_spanner_sessions_create = granted->can_spanner_sessions_create + project->granted_spanner_sessions_create 155 | permission granted_spanner_sessions_delete = granted->can_spanner_sessions_delete + project->granted_spanner_sessions_delete 156 | permission granted_spanner_sessions_get = granted->can_spanner_sessions_get + project->granted_spanner_sessions_get 157 | permission granted_spanner_sessions_list = granted->can_spanner_sessions_list + project->granted_spanner_sessions_list 158 | 159 | // Synthetic Database Operations Relations 160 | permission granted_spanner_databaseoperations_cancel = granted->can_spanner_databaseoperations_cancel + project->granted_spanner_databaseoperations_cancel 161 | permission granted_spanner_databaseoperations_delete = granted->can_spanner_databaseoperations_delete + project->granted_spanner_databaseoperations_delete 162 | permission granted_spanner_databaseoperations_get = granted->can_spanner_databaseoperations_get + project->granted_spanner_databaseoperations_get 163 | permission granted_spanner_databaseoperations_list = granted->can_spanner_databaseoperations_list + project->granted_spanner_databaseoperations_list 164 | 165 | // Synthetic Database Roles Relations 166 | permission granted_spanner_databaseroles_list = granted->can_spanner_databaseroles_list + project->granted_spanner_databaseroles_list 167 | permission granted_spanner_databaseroles_use = granted->can_spanner_databaseroles_use + project->granted_spanner_databaseroles_use 168 | } 169 | 170 | definition spanner_database { 171 | relation instance: spanner_instance 172 | relation granted: role 173 | 174 | // Database 175 | permission beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction + instance->granted_spanner_databases_beginorrollbackreadwritetransaction 176 | permission beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction + instance->granted_spanner_databases_beginpartitioneddmltransaction 177 | permission beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction + instance->granted_spanner_databases_beginreadonlytransaction 178 | permission create = granted->can_spanner_databases_create + instance->granted_spanner_databases_create 179 | permission drop = granted->can_spanner_databases_drop + instance->granted_spanner_databases_drop 180 | permission get = granted->can_spanner_databases_get + instance->granted_spanner_databases_get 181 | permission get_ddl = granted->can_spanner_databases_getddl + instance->granted_spanner_databases_getddl 182 | permission getiampolicy = granted->can_spanner_databases_getiampolicy + instance->granted_spanner_databases_getiampolicy 183 | permission list = granted->can_spanner_databases_list + instance->granted_spanner_databases_list 184 | permission partitionquery = granted->can_spanner_databases_partitionquery + instance->granted_spanner_databases_partitionquery 185 | permission partitionread = granted->can_spanner_databases_partitionread + instance->granted_spanner_databases_partitionread 186 | permission read = granted->can_spanner_databases_read + instance->granted_spanner_databases_read 187 | permission select = granted->can_spanner_databases_select + instance->granted_spanner_databases_select 188 | permission setiampolicy = granted->can_spanner_databases_setiampolicy + instance->granted_spanner_databases_setiampolicy 189 | permission update = granted->can_spanner_databases_update + instance->granted_spanner_databases_update 190 | permission updateddl = granted->can_spanner_databases_updateddl + instance->granted_spanner_databases_updateddl 191 | permission userolebasedaccess = granted->can_spanner_databases_userolebasedaccess + instance->granted_spanner_databases_userolebasedaccess 192 | permission write = granted->can_spanner_databases_write + instance->granted_spanner_databases_write 193 | 194 | // Sessions 195 | permission create_session = granted->can_spanner_sessions_create + instance->granted_spanner_sessions_create 196 | permission delete_session = granted->can_spanner_sessions_delete + instance->granted_spanner_sessions_delete 197 | permission get_session = granted->can_spanner_sessions_get + instance->granted_spanner_sessions_get 198 | permission list_sessions = granted->can_spanner_sessions_list + instance->granted_spanner_sessions_list 199 | 200 | // Database Operations 201 | permission cancel_operation = granted->can_spanner_databaseoperations_cancel + instance->granted_spanner_databaseoperations_cancel 202 | permission delete_operation = granted->can_spanner_databaseoperations_delete + instance->granted_spanner_databaseoperations_delete 203 | permission get_operation = granted->can_spanner_databaseoperations_get + instance->granted_spanner_databaseoperations_get 204 | permission list_operations = granted->can_spanner_databaseoperations_list + instance->granted_spanner_databaseoperations_list 205 | 206 | // Database Roles 207 | permission list_roles = granted->can_spanner_databaseroles_list + instance->granted_spanner_databaseroles_list 208 | permission use_role = granted->can_spanner_databaseroles_use + instance->granted_spanner_databaseroles_use 209 | } 210 | ``` 211 | -------------------------------------------------------------------------------- /schemas/multiple-validation-files/README.md: -------------------------------------------------------------------------------- 1 | ## Multiple Validation Files with a Single Schema 2 | 3 | This requires zed version v0.25.0. 4 | 5 | This folder demonstrates a structure for a schema and validation files that 6 | can be run in a single `zed validate` command and used as a template 7 | for writing multiple independent tests of a single schema. 8 | 9 | Running the following: 10 | 11 | ``` 12 | zed validate validations/* 13 | ``` 14 | 15 | in this folder will validate the schema and run all validations in all schema files. 16 | 17 | Note the use of `schemaFile: ` in the validation files - this allows the validation file to 18 | reference the schema without the schema needing to be inline. 19 | -------------------------------------------------------------------------------- /schemas/multiple-validation-files/schema.zed: -------------------------------------------------------------------------------- 1 | definition user {} 2 | 3 | definition role { 4 | relation bound_user: user 5 | 6 | relation spanner_databaseoperations_cancel: role 7 | relation spanner_databaseoperations_delete: role 8 | relation spanner_databaseoperations_get: role 9 | relation spanner_databaseoperations_list: role 10 | relation spanner_databaseroles_list: role 11 | relation spanner_databaseroles_use: role 12 | relation spanner_databases_beginorrollbackreadwritetransaction: role 13 | relation spanner_databases_beginpartitioneddmltransaction: role 14 | relation spanner_databases_beginreadonlytransaction: role 15 | relation spanner_databases_create: role 16 | relation spanner_databases_drop: role 17 | relation spanner_databases_get: role 18 | relation spanner_databases_getddl: role 19 | relation spanner_databases_getiampolicy: role 20 | relation spanner_databases_list: role 21 | relation spanner_databases_partitionquery: role 22 | relation spanner_databases_partitionread: role 23 | relation spanner_databases_read: role 24 | relation spanner_databases_select: role 25 | relation spanner_databases_setiampolicy: role 26 | relation spanner_databases_update: role 27 | relation spanner_databases_updateddl: role 28 | relation spanner_databases_userolebasedaccess: role 29 | relation spanner_databases_write: role 30 | relation spanner_instances_get: role 31 | relation spanner_instances_getiampolicy: role 32 | relation spanner_instances_list: role 33 | relation spanner_sessions_create: role 34 | relation spanner_sessions_delete: role 35 | relation spanner_sessions_get: role 36 | relation spanner_sessions_list: role 37 | 38 | permission can_spanner_databaseoperations_cancel = spanner_databaseoperations_cancel->bound_user 39 | permission can_spanner_databaseoperations_delete = spanner_databaseoperations_delete->bound_user 40 | permission can_spanner_databaseoperations_get = spanner_databaseoperations_get->bound_user 41 | permission can_spanner_databaseoperations_list = spanner_databaseoperations_list->bound_user 42 | permission can_spanner_databaseroles_list = spanner_databaseroles_list->bound_user 43 | permission can_spanner_databaseroles_use = spanner_databaseroles_use->bound_user 44 | permission can_spanner_databases_beginorrollbackreadwritetransaction = spanner_databases_beginorrollbackreadwritetransaction->bound_user 45 | permission can_spanner_databases_beginpartitioneddmltransaction = spanner_databases_beginpartitioneddmltransaction->bound_user 46 | permission can_spanner_databases_beginreadonlytransaction = spanner_databases_beginreadonlytransaction->bound_user 47 | permission can_spanner_databases_create = spanner_databases_create->bound_user 48 | permission can_spanner_databases_drop = spanner_databases_drop->bound_user 49 | permission can_spanner_databases_get = spanner_databases_get->bound_user 50 | permission can_spanner_databases_getddl = spanner_databases_getddl->bound_user 51 | permission can_spanner_databases_getiampolicy = spanner_databases_getiampolicy->bound_user 52 | permission can_spanner_databases_list = spanner_databases_list->bound_user 53 | permission can_spanner_databases_partitionquery = spanner_databases_partitionquery->bound_user 54 | permission can_spanner_databases_partitionread = spanner_databases_partitionread->bound_user 55 | permission can_spanner_databases_read = spanner_databases_read->bound_user 56 | permission can_spanner_databases_select = spanner_databases_select->bound_user 57 | permission can_spanner_databases_setiampolicy = spanner_databases_setiampolicy->bound_user 58 | permission can_spanner_databases_update = spanner_databases_update->bound_user 59 | permission can_spanner_databases_updateddl = spanner_databases_updateddl->bound_user 60 | permission can_spanner_databases_userolebasedaccess = spanner_databases_userolebasedaccess->bound_user 61 | permission can_spanner_databases_write = spanner_databases_write->bound_user 62 | permission can_spanner_instances_get = spanner_instances_get->bound_user 63 | permission can_spanner_instances_getiampolicy = spanner_instances_getiampolicy->bound_user 64 | permission can_spanner_instances_list = spanner_instances_list->bound_user 65 | permission can_spanner_sessions_create = spanner_sessions_create->bound_user 66 | permission can_spanner_sessions_delete = spanner_sessions_delete->bound_user 67 | permission can_spanner_sessions_get = spanner_sessions_get->bound_user 68 | permission can_spanner_sessions_list = spanner_sessions_list->bound_user 69 | } 70 | 71 | definition project { 72 | relation granted: role 73 | 74 | // Synthetic Instance Relations 75 | permission granted_spanner_instances_get = granted->can_spanner_instances_get 76 | permission granted_spanner_instances_getiampolicy = granted->can_spanner_instances_getiampolicy 77 | permission granted_spanner_instances_list = granted->can_spanner_instances_list 78 | 79 | // Synthetic Database Relations 80 | permission granted_spanner_databases_beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction 81 | permission granted_spanner_databases_beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction 82 | permission granted_spanner_databases_beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction 83 | permission granted_spanner_databases_create = granted->can_spanner_databases_create 84 | permission granted_spanner_databases_drop = granted->can_spanner_databases_drop 85 | permission granted_spanner_databases_get = granted->can_spanner_databases_get 86 | permission granted_spanner_databases_getddl = granted->can_spanner_databases_getddl 87 | permission granted_spanner_databases_getiampolicy = granted->can_spanner_databases_getiampolicy 88 | permission granted_spanner_databases_list = granted->can_spanner_databases_list 89 | permission granted_spanner_databases_partitionquery = granted->can_spanner_databases_partitionquery 90 | permission granted_spanner_databases_partitionread = granted->can_spanner_databases_partitionread 91 | permission granted_spanner_databases_read = granted->can_spanner_databases_read 92 | permission granted_spanner_databases_select = granted->can_spanner_databases_select 93 | permission granted_spanner_databases_setiampolicy = granted->can_spanner_databases_setiampolicy 94 | permission granted_spanner_databases_update = granted->can_spanner_databases_update 95 | permission granted_spanner_databases_updateddl = granted->can_spanner_databases_updateddl 96 | permission granted_spanner_databases_userolebasedaccess = granted->can_spanner_databases_userolebasedaccess 97 | permission granted_spanner_databases_write = granted->can_spanner_databases_write 98 | 99 | // Synthetic Sessions Relations 100 | permission granted_spanner_sessions_create = granted->can_spanner_sessions_create 101 | permission granted_spanner_sessions_delete = granted->can_spanner_sessions_delete 102 | permission granted_spanner_sessions_get = granted->can_spanner_sessions_get 103 | permission granted_spanner_sessions_list = granted->can_spanner_sessions_list 104 | 105 | // Synthetic Database Operations Relations 106 | permission granted_spanner_databaseoperations_cancel = granted->can_spanner_databaseoperations_cancel 107 | permission granted_spanner_databaseoperations_delete = granted->can_spanner_databaseoperations_delete 108 | permission granted_spanner_databaseoperations_get = granted->can_spanner_databaseoperations_get 109 | permission granted_spanner_databaseoperations_list = granted->can_spanner_databaseoperations_list 110 | 111 | // Synthetic Database Roles Relations 112 | permission granted_spanner_databaseroles_list = granted->can_spanner_databaseroles_list 113 | permission granted_spanner_databaseroles_use = granted->can_spanner_databaseroles_use 114 | } 115 | 116 | definition spanner_instance { 117 | relation project: project 118 | relation granted: role 119 | 120 | permission get = granted->can_spanner_instances_get + project->granted_spanner_instances_get 121 | permission getiampolicy = granted->can_spanner_instances_getiampolicy + project->granted_spanner_instances_getiampolicy 122 | permission list = granted->can_spanner_instances_list + project->granted_spanner_instances_list 123 | 124 | // Synthetic Database Relations 125 | permission granted_spanner_databases_beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction + project->granted_spanner_databases_beginorrollbackreadwritetransaction 126 | permission granted_spanner_databases_beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction + project->granted_spanner_databases_beginpartitioneddmltransaction 127 | permission granted_spanner_databases_beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction + project->granted_spanner_databases_beginreadonlytransaction 128 | permission granted_spanner_databases_create = granted->can_spanner_databases_create + project->granted_spanner_databases_create 129 | permission granted_spanner_databases_drop = granted->can_spanner_databases_drop + project->granted_spanner_databases_drop 130 | permission granted_spanner_databases_get = granted->can_spanner_databases_get + project->granted_spanner_databases_get 131 | permission granted_spanner_databases_getddl = granted->can_spanner_databases_getddl + project->granted_spanner_databases_getddl 132 | permission granted_spanner_databases_getiampolicy = granted->can_spanner_databases_getiampolicy + project->granted_spanner_databases_getiampolicy 133 | permission granted_spanner_databases_list = granted->can_spanner_databases_list + project->granted_spanner_databases_list 134 | permission granted_spanner_databases_partitionquery = granted->can_spanner_databases_partitionquery + project->granted_spanner_databases_partitionquery 135 | permission granted_spanner_databases_partitionread = granted->can_spanner_databases_partitionread + project->granted_spanner_databases_partitionread 136 | permission granted_spanner_databases_read = granted->can_spanner_databases_read + project->granted_spanner_databases_read 137 | permission granted_spanner_databases_select = granted->can_spanner_databases_select + project->granted_spanner_databases_select 138 | permission granted_spanner_databases_setiampolicy = granted->can_spanner_databases_setiampolicy + project->granted_spanner_databases_setiampolicy 139 | permission granted_spanner_databases_update = granted->can_spanner_databases_update + project->granted_spanner_databases_update 140 | permission granted_spanner_databases_updateddl = granted->can_spanner_databases_updateddl + project->granted_spanner_databases_updateddl 141 | permission granted_spanner_databases_userolebasedaccess = granted->can_spanner_databases_userolebasedaccess + project->granted_spanner_databases_userolebasedaccess 142 | permission granted_spanner_databases_write = granted->can_spanner_databases_write + project->granted_spanner_databases_write 143 | 144 | // Synthetic Sessions Relations 145 | permission granted_spanner_sessions_create = granted->can_spanner_sessions_create + project->granted_spanner_sessions_create 146 | permission granted_spanner_sessions_delete = granted->can_spanner_sessions_delete + project->granted_spanner_sessions_delete 147 | permission granted_spanner_sessions_get = granted->can_spanner_sessions_get + project->granted_spanner_sessions_get 148 | permission granted_spanner_sessions_list = granted->can_spanner_sessions_list + project->granted_spanner_sessions_list 149 | 150 | // Synthetic Database Operations Relations 151 | permission granted_spanner_databaseoperations_cancel = granted->can_spanner_databaseoperations_cancel + project->granted_spanner_databaseoperations_cancel 152 | permission granted_spanner_databaseoperations_delete = granted->can_spanner_databaseoperations_delete + project->granted_spanner_databaseoperations_delete 153 | permission granted_spanner_databaseoperations_get = granted->can_spanner_databaseoperations_get + project->granted_spanner_databaseoperations_get 154 | permission granted_spanner_databaseoperations_list = granted->can_spanner_databaseoperations_list + project->granted_spanner_databaseoperations_list 155 | 156 | // Synthetic Database Roles Relations 157 | permission granted_spanner_databaseroles_list = granted->can_spanner_databaseroles_list + project->granted_spanner_databaseroles_list 158 | permission granted_spanner_databaseroles_use = granted->can_spanner_databaseroles_use + project->granted_spanner_databaseroles_use 159 | } 160 | 161 | definition spanner_database { 162 | relation instance: spanner_instance 163 | relation granted: role 164 | 165 | // Database 166 | permission beginorrollbackreadwritetransaction = granted->can_spanner_databases_beginorrollbackreadwritetransaction + instance->granted_spanner_databases_beginorrollbackreadwritetransaction 167 | permission beginpartitioneddmltransaction = granted->can_spanner_databases_beginpartitioneddmltransaction + instance->granted_spanner_databases_beginpartitioneddmltransaction 168 | permission beginreadonlytransaction = granted->can_spanner_databases_beginreadonlytransaction + instance->granted_spanner_databases_beginreadonlytransaction 169 | permission create = granted->can_spanner_databases_create + instance->granted_spanner_databases_create 170 | permission drop = granted->can_spanner_databases_drop + instance->granted_spanner_databases_drop 171 | permission get = granted->can_spanner_databases_get + instance->granted_spanner_databases_get 172 | permission get_ddl = granted->can_spanner_databases_getddl + instance->granted_spanner_databases_getddl 173 | permission getiampolicy = granted->can_spanner_databases_getiampolicy + instance->granted_spanner_databases_getiampolicy 174 | permission list = granted->can_spanner_databases_list + instance->granted_spanner_databases_list 175 | permission partitionquery = granted->can_spanner_databases_partitionquery + instance->granted_spanner_databases_partitionquery 176 | permission partitionread = granted->can_spanner_databases_partitionread + instance->granted_spanner_databases_partitionread 177 | permission read = granted->can_spanner_databases_read + instance->granted_spanner_databases_read 178 | permission select = granted->can_spanner_databases_select + instance->granted_spanner_databases_select 179 | permission setiampolicy = granted->can_spanner_databases_setiampolicy + instance->granted_spanner_databases_setiampolicy 180 | permission update = granted->can_spanner_databases_update + instance->granted_spanner_databases_update 181 | permission updateddl = granted->can_spanner_databases_updateddl + instance->granted_spanner_databases_updateddl 182 | permission userolebasedaccess = granted->can_spanner_databases_userolebasedaccess + instance->granted_spanner_databases_userolebasedaccess 183 | permission write = granted->can_spanner_databases_write + instance->granted_spanner_databases_write 184 | 185 | // Sessions 186 | permission create_session = granted->can_spanner_sessions_create + instance->granted_spanner_sessions_create 187 | permission delete_session = granted->can_spanner_sessions_delete + instance->granted_spanner_sessions_delete 188 | permission get_session = granted->can_spanner_sessions_get + instance->granted_spanner_sessions_get 189 | permission list_sessions = granted->can_spanner_sessions_list + instance->granted_spanner_sessions_list 190 | 191 | // Database Operations 192 | permission cancel_operation = granted->can_spanner_databaseoperations_cancel + instance->granted_spanner_databaseoperations_cancel 193 | permission delete_operation = granted->can_spanner_databaseoperations_delete + instance->granted_spanner_databaseoperations_delete 194 | permission get_operation = granted->can_spanner_databaseoperations_get + instance->granted_spanner_databaseoperations_get 195 | permission list_operations = granted->can_spanner_databaseoperations_list + instance->granted_spanner_databaseoperations_list 196 | 197 | // Database Roles 198 | permission list_roles = granted->can_spanner_databaseroles_list + instance->granted_spanner_databaseroles_list 199 | permission use_role = granted->can_spanner_databaseroles_use + instance->granted_spanner_databaseroles_use 200 | } 201 | -------------------------------------------------------------------------------- /schemas/multiple-validation-files/validations/admin-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schemaFile: "../schema.zed" 3 | relationships: |- 4 | spanner_database:db1#instance@spanner_instance:instance1 5 | spanner_instance:instance1#project@project:proj1 6 | 7 | // Add permissions to "admin" role 8 | role:spanner_database_admin#spanner_databaseoperations_cancel@role:spanner_database_admin 9 | role:spanner_database_admin#spanner_databaseoperations_delete@role:spanner_database_admin 10 | role:spanner_database_admin#spanner_databaseoperations_get@role:spanner_database_admin 11 | role:spanner_database_admin#spanner_databaseoperations_list@role:spanner_database_admin 12 | role:spanner_database_admin#spanner_databaseroles_list@role:spanner_database_admin 13 | role:spanner_database_admin#spanner_databaseroles_use@role:spanner_database_admin 14 | role:spanner_database_admin#spanner_databases_beginorrollbackreadwritetransaction@role:spanner_database_admin 15 | role:spanner_database_admin#spanner_databases_beginpartitioneddmltransaction@role:spanner_database_admin 16 | role:spanner_database_admin#spanner_databases_beginreadonlytransaction@role:spanner_database_admin 17 | role:spanner_database_admin#spanner_databases_create@role:spanner_database_admin 18 | role:spanner_database_admin#spanner_databases_drop@role:spanner_database_admin 19 | role:spanner_database_admin#spanner_databases_get@role:spanner_database_admin 20 | role:spanner_database_admin#spanner_databases_getddl@role:spanner_database_admin 21 | role:spanner_database_admin#spanner_databases_getiampolicy@role:spanner_database_admin 22 | role:spanner_database_admin#spanner_databases_list@role:spanner_database_admin 23 | role:spanner_database_admin#spanner_databases_partitionquery@role:spanner_database_admin 24 | role:spanner_database_admin#spanner_databases_partitionread@role:spanner_database_admin 25 | role:spanner_database_admin#spanner_databases_read@role:spanner_database_admin 26 | role:spanner_database_admin#spanner_databases_select@role:spanner_database_admin 27 | role:spanner_database_admin#spanner_databases_setiampolicy@role:spanner_database_admin 28 | role:spanner_database_admin#spanner_databases_update@role:spanner_database_admin 29 | role:spanner_database_admin#spanner_databases_updateddl@role:spanner_database_admin 30 | role:spanner_database_admin#spanner_databases_userolebasedaccess@role:spanner_database_admin 31 | role:spanner_database_admin#spanner_databases_write@role:spanner_database_admin 32 | role:spanner_database_admin#spanner_instances_get@role:spanner_database_admin 33 | role:spanner_database_admin#spanner_instances_getiampolicy@role:spanner_database_admin 34 | role:spanner_database_admin#spanner_instances_list@role:spanner_database_admin 35 | role:spanner_database_admin#spanner_sessions_create@role:spanner_database_admin 36 | role:spanner_database_admin#spanner_sessions_delete@role:spanner_database_admin 37 | role:spanner_database_admin#spanner_sessions_get@role:spanner_database_admin 38 | role:spanner_database_admin#spanner_sessions_list@role:spanner_database_admin 39 | 40 | // Grant admin role to a specific user on a resource 41 | role:spanner_database_admin#bound_user@user:specific_db_admin 42 | spanner_database:db1#granted@role:spanner_database_admin 43 | assertions: 44 | assertTrue: 45 | - "spanner_database:db1#drop@user:specific_db_admin" 46 | - "spanner_database:db1#delete_session@user:specific_db_admin" 47 | assertFalse: 48 | # Can't drop a database you don't have access to 49 | - "spanner_database:db2#drop@user:specific_db_admin" 50 | validation: 51 | spanner_database:db1#drop: 52 | - "[user:specific_db_admin] is " 53 | spanner_database:db1#read: 54 | - "[user:specific_db_admin] is " 55 | -------------------------------------------------------------------------------- /schemas/multiple-validation-files/validations/reader-role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schemaFile: "../schema.zed" 3 | relationships: |- 4 | spanner_database:db1#instance@spanner_instance:instance1 5 | spanner_instance:instance1#project@project:proj1 6 | 7 | // Add permissions to "reader" role 8 | role:spanner_database_reader#spanner_databases_beginreadonlytransaction@role:spanner_database_reader 9 | role:spanner_database_reader#spanner_databases_getddl@role:spanner_database_reader 10 | role:spanner_database_reader#spanner_databases_partitionquery@role:spanner_database_reader 11 | role:spanner_database_reader#spanner_databases_partitionread@role:spanner_database_reader 12 | role:spanner_database_reader#spanner_databases_read@role:spanner_database_reader 13 | role:spanner_database_reader#spanner_databases_select@role:spanner_database_reader 14 | role:spanner_database_reader#spanner_instances_get@role:spanner_database_reader 15 | role:spanner_database_reader#spanner_sessions_create@role:spanner_database_reader 16 | role:spanner_database_reader#spanner_sessions_delete@role:spanner_database_reader 17 | role:spanner_database_reader#spanner_sessions_get@role:spanner_database_reader 18 | role:spanner_database_reader#spanner_sessions_list@role:spanner_database_reader 19 | 20 | // Grant reader role to a specific user on a resource 21 | role:spanner_database_reader#bound_user@user:project_db_reader 22 | project:proj1#granted@role:spanner_database_reader 23 | assertions: 24 | assertTrue: 25 | - "spanner_database:db1#read@user:project_db_reader" 26 | - "spanner_database:db1#list_sessions@user:project_db_reader" 27 | assertFalse: 28 | # Can't drop a database you don't have access to 29 | - "spanner_database:db2#drop@user:project_db_reader" 30 | validation: 31 | spanner_database:db1#read: 32 | - "[user:project_db_reader] is " 33 | -------------------------------------------------------------------------------- /schemas/superuser/README.md: -------------------------------------------------------------------------------- 1 | # Super-admin / site-wide permissions 2 | 3 | Models providing site-wide (or superuser) permissions for all resources of a specific type 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | definition platform { 11 | relation administrator: user 12 | permission super_admin = administrator 13 | } 14 | 15 | definition organization { 16 | // The platform is generally a singleton pointing to the same 17 | // platform object, on which the superuser is in turn granted 18 | // access. 19 | relation platform: platform 20 | permission admin = platform->super_admin 21 | } 22 | 23 | definition resource { 24 | relation owner: user | organization 25 | permission admin = owner + owner->admin 26 | } 27 | 28 | definition user {} 29 | ``` 30 | -------------------------------------------------------------------------------- /schemas/superuser/schema-and-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schema: |- 3 | definition platform { 4 | relation administrator: user 5 | permission super_admin = administrator 6 | } 7 | 8 | definition organization { 9 | // The platform is generally a singleton pointing to the same 10 | // platform object, on which the superuser is in turn granted 11 | // access. 12 | relation platform: platform 13 | permission admin = platform->super_admin 14 | } 15 | 16 | definition resource { 17 | relation owner: user | organization 18 | permission admin = owner + owner->admin 19 | } 20 | 21 | definition user {} 22 | relationships: |- 23 | platform:evilempire#administrator@user:drevil 24 | organization:virtucon#platform@platform:evilempire 25 | resource:lasers#owner@organization:virtucon 26 | assertions: 27 | assertTrue: 28 | - "resource:lasers#admin@user:drevil" 29 | assertFalse: null 30 | validation: null 31 | -------------------------------------------------------------------------------- /schemas/user-defined-roles/README.md: -------------------------------------------------------------------------------- 1 | # User Defined Roles 2 | 3 | Models user defined custom roles. Blog post: https://authzed.com/blog/user-defined-roles/ 4 | 5 | --- 6 | 7 | ## Schema 8 | 9 | ``` 10 | definition user {} 11 | 12 | definition project { 13 | relation issue_creator: role#member 14 | relation issue_assigner: role#member 15 | relation any_issue_resolver: role#member 16 | relation assigned_issue_resolver: role#member 17 | relation comment_creator: role#member 18 | relation comment_deleter: role#member 19 | relation role_manager: role#member 20 | 21 | permission create_issue = issue_creator 22 | permission create_role = role_manager 23 | } 24 | 25 | definition role { 26 | relation project: project 27 | relation member: user 28 | relation built_in_role: project 29 | 30 | permission delete = project->role_manager - built_in_role->role_manager 31 | permission add_user = project->role_manager 32 | permission add_permission = project->role_manager - built_in_role->role_manager 33 | permission remove_permission = project->role_manager - built_in_role->role_manager 34 | } 35 | 36 | definition issue { 37 | relation project: project 38 | relation assigned: user 39 | 40 | permission assign = project->issue_assigner 41 | permission resolve = (project->assigned_issue_resolver & assigned) + project->any_issue_resolver 42 | permission create_comment = project->comment_creator 43 | 44 | // synthetic relation 45 | permission project_comment_deleter = project->comment_deleter 46 | } 47 | 48 | definition comment { 49 | relation issue: issue 50 | permission delete = issue->project_comment_deleter 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /schemas/user-defined-roles/schema-and-data.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | schema: | 3 | definition user {} 4 | 5 | definition project { 6 | relation issue_creator: role#member 7 | relation issue_assigner: role#member 8 | relation any_issue_resolver: role#member 9 | relation assigned_issue_resolver: role#member 10 | relation comment_creator: role#member 11 | relation comment_deleter: role#member 12 | relation role_manager: role#member 13 | 14 | permission create_issue = issue_creator 15 | permission create_role = role_manager 16 | } 17 | 18 | definition role { 19 | relation project: project 20 | relation member: user 21 | relation built_in_role: project 22 | 23 | permission delete = project->role_manager - built_in_role->role_manager 24 | permission add_user = project->role_manager 25 | permission add_permission = project->role_manager - built_in_role->role_manager 26 | permission remove_permission = project->role_manager - built_in_role->role_manager 27 | } 28 | 29 | definition issue { 30 | relation project: project 31 | relation assigned: user 32 | 33 | permission assign = project->issue_assigner 34 | permission resolve = (project->assigned_issue_resolver & assigned) + project->any_issue_resolver 35 | permission create_comment = project->comment_creator 36 | 37 | // synthetic relation 38 | permission project_comment_deleter = project->comment_deleter 39 | } 40 | 41 | definition comment { 42 | relation issue: issue 43 | permission delete = issue->project_comment_deleter 44 | } 45 | relationships: | 46 | issue:move_the_servers#project@project:pied_piper 47 | issue:move_the_servers#assigned@user:gilfoyle 48 | 49 | issue:too_slow#project@project:pied_piper 50 | comment:try_middle_out#issue@issue:too_slow 51 | 52 | role:admin#project@project:pied_piper 53 | role:admin#built_in_role@project:pied_piper 54 | role:developer#project@project:pied_piper 55 | role:developer#built_in_role@project:pied_piper 56 | role:user#project@project:pied_piper 57 | role:user#built_in_role@project:pied_piper 58 | role:project_manager#project@project:pied_piper 59 | role:legal#project@project:pied_piper 60 | 61 | project:pied_piper#issue_creator@role:admin#member 62 | project:pied_piper#issue_creator@role:developer#member 63 | project:pied_piper#issue_creator@role:user#member 64 | 65 | project:pied_piper#issue_assigner@role:admin#member 66 | project:pied_piper#issue_assigner@role:project_manager#member 67 | 68 | project:pied_piper#any_issue_resolver@role:admin#member 69 | project:pied_piper#any_issue_resolver@role:project_manager#member 70 | 71 | project:pied_piper#assigned_issue_resolver@role:admin#member 72 | project:pied_piper#assigned_issue_resolver@role:developer#member 73 | 74 | project:pied_piper#comment_creator@role:admin#member 75 | project:pied_piper#comment_creator@role:developer#member 76 | project:pied_piper#comment_creator@role:user#member 77 | 78 | project:pied_piper#comment_deleter@role:admin#member 79 | project:pied_piper#comment_deleter@role:legal#member 80 | 81 | project:pied_piper#role_manager@role:admin#member 82 | 83 | role:admin#member@user:richard 84 | role:developer#member@user:gilfoyle 85 | role:user#member@user:monica 86 | role:project_manager#member@user:jared 87 | role:legal#member@user:ron 88 | assertions: 89 | assertTrue: [] 90 | assertFalse: [] 91 | validation: 92 | comment:try_middle_out#delete: 93 | - "[role:admin#member] is " 94 | - "[role:legal#member] is " 95 | - "[user:richard] is " 96 | - "[user:ron] is " 97 | issue:move_the_servers#assign: 98 | - "[role:admin#member] is " 99 | - "[role:project_manager#member] is " 100 | - "[user:jared] is " 101 | - "[user:richard] is " 102 | issue:move_the_servers#resolve: 103 | - "[role:admin#member] is " 104 | - "[role:project_manager#member] is " 105 | - "[user:gilfoyle] is /" 106 | - "[user:jared] is " 107 | - "[user:richard] is " 108 | issue:too_slow#assign: 109 | - "[role:admin#member] is " 110 | - "[role:project_manager#member] is " 111 | - "[user:jared] is " 112 | - "[user:richard] is " 113 | issue:too_slow#create_comment: 114 | - "[role:admin#member] is " 115 | - "[role:developer#member] is " 116 | - "[role:user#member] is " 117 | - "[user:gilfoyle] is " 118 | - "[user:monica] is " 119 | - "[user:richard] is " 120 | issue:too_slow#resolve: 121 | - "[role:admin#member] is " 122 | - "[role:project_manager#member] is " 123 | - "[user:jared] is " 124 | - "[user:richard] is " 125 | project:pied_piper#create_issue: 126 | - "[role:admin#member] is " 127 | - "[role:developer#member] is " 128 | - "[role:user#member] is " 129 | - "[user:gilfoyle] is " 130 | - "[user:monica] is " 131 | - "[user:richard] is " 132 | role:admin#add_user: 133 | - "[role:admin#member] is " 134 | - "[user:richard] is " 135 | role:admin#delete: [] 136 | role:project_manager#add_user: 137 | - "[role:admin#member] is " 138 | - "[user:richard] is " 139 | role:project_manager#delete: 140 | - "[role:admin#member] is " 141 | - "[user:richard] is " 142 | -------------------------------------------------------------------------------- /spicedb-as-library/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/authzed/examples/spicedb-as-library 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/authzed/authzed-go v0.9.1-0.20230830212047-e1e7da6e877d 7 | github.com/authzed/spicedb v1.25.0 8 | ) 9 | 10 | require ( 11 | buf.build/gen/go/gogo/protobuf/protocolbuffers/go v1.31.0-20210810001428-4df00b267f94.1 // indirect 12 | buf.build/gen/go/prometheus/prometheus/protocolbuffers/go v1.31.0-20230726221845-41588ce133c8.1 // indirect 13 | cloud.google.com/go v0.110.6 // indirect 14 | cloud.google.com/go/compute v1.22.0 // indirect 15 | cloud.google.com/go/compute/metadata v0.2.3 // indirect 16 | cloud.google.com/go/iam v1.1.1 // indirect 17 | cloud.google.com/go/longrunning v0.5.1 // indirect 18 | cloud.google.com/go/spanner v1.47.0 // indirect 19 | github.com/IBM/pgxpoolprometheus v1.1.1 // indirect 20 | github.com/Masterminds/squirrel v1.5.4 // indirect 21 | github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect 22 | github.com/authzed/cel-go v0.17.5 // indirect 23 | github.com/authzed/consistent v0.1.0 // indirect 24 | github.com/authzed/grpcutil v0.0.0-20230703173955-bdd0ac3f16a5 // indirect 25 | github.com/benbjohnson/clock v1.3.5 // indirect 26 | github.com/beorn7/perks v1.0.1 // indirect 27 | github.com/cenkalti/backoff/v4 v4.2.1 // indirect 28 | github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect 29 | github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect 30 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 31 | github.com/cloudspannerecosystem/spanner-change-streams-tail v0.3.1 // indirect 32 | github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect 33 | github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect 34 | github.com/creasty/defaults v1.7.0 // indirect 35 | github.com/dalzilio/rudd v1.1.1-0.20230806153452-9e08a6ea8170 // indirect 36 | github.com/davecgh/go-spew v1.1.1 // indirect 37 | github.com/dlmiddlecote/sqlstats v1.0.2 // indirect 38 | github.com/dustin/go-humanize v1.0.1 // indirect 39 | github.com/ecordell/optgen v0.0.10-0.20230609182709-018141bf9698 // indirect 40 | github.com/emicklei/go-restful/v3 v3.10.2 // indirect 41 | github.com/emirpasic/gods v1.18.1 // indirect 42 | github.com/envoyproxy/go-control-plane v0.11.1 // indirect 43 | github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect 44 | github.com/exaring/otelpgx v0.5.0 // indirect 45 | github.com/fatih/color v1.15.0 // indirect 46 | github.com/felixge/httpsnoop v1.0.3 // indirect 47 | github.com/fsnotify/fsnotify v1.6.0 // indirect 48 | github.com/go-logr/logr v1.2.4 // indirect 49 | github.com/go-logr/stdr v1.2.2 // indirect 50 | github.com/go-logr/zerologr v1.2.3 // indirect 51 | github.com/go-openapi/jsonpointer v0.20.0 // indirect 52 | github.com/go-openapi/jsonreference v0.20.2 // indirect 53 | github.com/go-openapi/swag v0.22.4 // indirect 54 | github.com/go-sql-driver/mysql v1.7.1 // indirect 55 | github.com/gogo/protobuf v1.3.2 // indirect 56 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 57 | github.com/golang/protobuf v1.5.3 // indirect 58 | github.com/golang/snappy v0.0.4 // indirect 59 | github.com/google/gnostic v0.6.9 // indirect 60 | github.com/google/go-cmp v0.5.9 // indirect 61 | github.com/google/go-github/v43 v43.0.0 // indirect 62 | github.com/google/go-querystring v1.1.0 // indirect 63 | github.com/google/gofuzz v1.2.0 // indirect 64 | github.com/google/s2a-go v0.1.4 // indirect 65 | github.com/google/uuid v1.3.0 // indirect 66 | github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect 67 | github.com/googleapis/gax-go/v2 v2.12.0 // indirect 68 | github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect 69 | github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 // indirect 70 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect 71 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.1 // indirect 72 | github.com/hashicorp/errwrap v1.1.0 // indirect 73 | github.com/hashicorp/go-immutable-radix v1.3.1 // indirect 74 | github.com/hashicorp/go-memdb v1.3.4 // indirect 75 | github.com/hashicorp/go-multierror v1.1.1 // indirect 76 | github.com/hashicorp/golang-lru v0.5.4 // indirect 77 | github.com/hashicorp/hcl v1.0.0 // indirect 78 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 79 | github.com/influxdata/tdigest v0.0.1 // indirect 80 | github.com/jackc/pgio v1.0.0 // indirect 81 | github.com/jackc/pgpassfile v1.0.0 // indirect 82 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 83 | github.com/jackc/pgx-zerolog v0.0.0-20230315001418-f978528409eb // indirect 84 | github.com/jackc/pgx/v5 v5.4.2 // indirect 85 | github.com/jackc/puddle/v2 v2.2.1 // indirect 86 | github.com/joho/godotenv v1.5.1 // indirect 87 | github.com/josharian/intern v1.0.0 // indirect 88 | github.com/json-iterator/go v1.1.12 // indirect 89 | github.com/jzelinskie/cobrautil/v2 v2.0.0-20230825161137-b46695920a60 // indirect 90 | github.com/jzelinskie/stringz v0.0.2 // indirect 91 | github.com/klauspost/compress v1.16.7 // indirect 92 | github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect 93 | github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect 94 | github.com/lthibault/jitterbug v2.0.0+incompatible // indirect 95 | github.com/magiconair/properties v1.8.7 // indirect 96 | github.com/mailru/easyjson v0.7.7 // indirect 97 | github.com/mattn/go-colorable v0.1.13 // indirect 98 | github.com/mattn/go-isatty v0.0.19 // indirect 99 | github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect 100 | github.com/mitchellh/mapstructure v1.5.0 // indirect 101 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 102 | github.com/modern-go/reflect2 v1.0.2 // indirect 103 | github.com/mostynb/go-grpc-compression v1.2.0 // indirect 104 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 105 | github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79 // indirect 106 | github.com/outcaste-io/ristretto v0.2.3 // indirect 107 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect 108 | github.com/pelletier/go-toml/v2 v2.0.9 // indirect 109 | github.com/pkg/errors v0.9.1 // indirect 110 | github.com/pmezard/go-difflib v1.0.0 // indirect 111 | github.com/prometheus/client_golang v1.16.0 // indirect 112 | github.com/prometheus/client_model v0.4.0 // indirect 113 | github.com/prometheus/common v0.44.0 // indirect 114 | github.com/prometheus/procfs v0.11.0 // indirect 115 | github.com/rs/cors v1.9.0 // indirect 116 | github.com/rs/zerolog v1.29.1 // indirect 117 | github.com/samber/lo v1.38.1 // indirect 118 | github.com/scylladb/go-set v1.0.2 // indirect 119 | github.com/sean-/sysexits v1.0.0 // indirect 120 | github.com/shopspring/decimal v1.3.1 // indirect 121 | github.com/spf13/afero v1.9.5 // indirect 122 | github.com/spf13/cast v1.5.1 // indirect 123 | github.com/spf13/cobra v1.7.0 // indirect 124 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 125 | github.com/spf13/pflag v1.0.5 // indirect 126 | github.com/spf13/viper v1.16.0 // indirect 127 | github.com/stoewer/go-strcase v1.3.0 // indirect 128 | github.com/stretchr/testify v1.8.4 // indirect 129 | github.com/subosito/gotenv v1.4.2 // indirect 130 | go.opencensus.io v0.24.0 // indirect 131 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 // indirect 132 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect 133 | go.opentelemetry.io/contrib/propagators/b3 v1.17.0 // indirect 134 | go.opentelemetry.io/contrib/propagators/ot v1.17.0 // indirect 135 | go.opentelemetry.io/otel v1.16.0 // indirect 136 | go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect 137 | go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect 138 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect 139 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect 140 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect 141 | go.opentelemetry.io/otel/metric v1.16.0 // indirect 142 | go.opentelemetry.io/otel/sdk v1.16.0 // indirect 143 | go.opentelemetry.io/otel/trace v1.16.0 // indirect 144 | go.opentelemetry.io/proto/otlp v1.0.0 // indirect 145 | go.uber.org/atomic v1.11.0 // indirect 146 | go.uber.org/multierr v1.11.0 // indirect 147 | golang.org/x/crypto v0.11.0 // indirect 148 | golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect 149 | golang.org/x/mod v0.12.0 // indirect 150 | golang.org/x/net v0.12.0 // indirect 151 | golang.org/x/oauth2 v0.10.0 // indirect 152 | golang.org/x/sync v0.3.0 // indirect 153 | golang.org/x/sys v0.10.0 // indirect 154 | golang.org/x/term v0.10.0 // indirect 155 | golang.org/x/text v0.11.0 // indirect 156 | golang.org/x/time v0.3.0 // indirect 157 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 158 | google.golang.org/api v0.134.0 // indirect 159 | google.golang.org/appengine v1.6.7 // indirect 160 | google.golang.org/genproto v0.0.0-20230724170836-66ad5b6ff146 // indirect 161 | google.golang.org/genproto/googleapis/api v0.0.0-20230724170836-66ad5b6ff146 // indirect 162 | google.golang.org/genproto/googleapis/rpc v0.0.0-20230724170836-66ad5b6ff146 // indirect 163 | google.golang.org/grpc v1.56.2 // indirect 164 | google.golang.org/protobuf v1.31.0 // indirect 165 | gopkg.in/inf.v0 v0.9.1 // indirect 166 | gopkg.in/ini.v1 v1.67.0 // indirect 167 | gopkg.in/yaml.v2 v2.4.0 // indirect 168 | gopkg.in/yaml.v3 v3.0.1 // indirect 169 | k8s.io/api v0.27.2 // indirect 170 | k8s.io/apimachinery v0.27.2 // indirect 171 | k8s.io/client-go v0.27.2 // indirect 172 | k8s.io/klog/v2 v2.90.1 // indirect 173 | k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect 174 | k8s.io/utils v0.0.0-20230209194617-a36077c30491 // indirect 175 | sigs.k8s.io/controller-runtime v0.15.0 // indirect 176 | sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect 177 | sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect 178 | sigs.k8s.io/yaml v1.3.0 // indirect 179 | ) 180 | -------------------------------------------------------------------------------- /spicedb-as-library/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | 7 | v1 "github.com/authzed/authzed-go/proto/authzed/api/v1" 8 | "github.com/authzed/spicedb/pkg/cmd/datastore" 9 | "github.com/authzed/spicedb/pkg/cmd/server" 10 | "github.com/authzed/spicedb/pkg/cmd/util" 11 | ) 12 | 13 | func main() { 14 | ctx, cancel := context.WithCancel(context.Background()) 15 | defer cancel() 16 | 17 | srv, err := newServer(ctx) 18 | if err != nil { 19 | log.Fatal("unable to init server: %w", err) 20 | } 21 | 22 | conn, err := srv.GRPCDialContext(ctx) 23 | if err != nil { 24 | log.Fatal("unable to get gRPC connection: %w", err) 25 | } 26 | 27 | schemaSrv := v1.NewSchemaServiceClient(conn) 28 | permSrv := v1.NewPermissionsServiceClient(conn) 29 | 30 | go func() { 31 | if err := srv.Run(ctx); err != nil { 32 | log.Print("error while shutting down server: %w", err) 33 | } 34 | }() 35 | 36 | _, err = schemaSrv.WriteSchema(ctx, &v1.WriteSchemaRequest{ 37 | Schema: `definition user {} 38 | definition resource { 39 | relation viewer: user 40 | permission view = viewer 41 | }`, 42 | }) 43 | if err != nil { 44 | log.Fatal("unable to get gRPC connection: %w", err) 45 | } 46 | 47 | resp, err := permSrv.WriteRelationships(ctx, &v1.WriteRelationshipsRequest{Updates: []*v1.RelationshipUpdate{ 48 | { 49 | Operation: v1.RelationshipUpdate_OPERATION_CREATE, 50 | Relationship: &v1.Relationship{ 51 | Resource: &v1.ObjectReference{ 52 | ObjectId: "my_book", 53 | ObjectType: "resource", 54 | }, 55 | Relation: "viewer", 56 | Subject: &v1.SubjectReference{ 57 | Object: &v1.ObjectReference{ 58 | ObjectId: "john_doe", 59 | ObjectType: "user", 60 | }, 61 | }, 62 | }, 63 | }, 64 | }}) 65 | if err != nil { 66 | log.Fatal("unable to get gRPC connection: %w", err) 67 | } 68 | 69 | token := resp.GetWrittenAt() 70 | checkResp, err := permSrv.CheckPermission(ctx, &v1.CheckPermissionRequest{ 71 | Permission: "view", 72 | Consistency: &v1.Consistency{Requirement: &v1.Consistency_AtLeastAsFresh{AtLeastAsFresh: token}}, 73 | Resource: &v1.ObjectReference{ 74 | ObjectId: "my_book", 75 | ObjectType: "resource", 76 | }, 77 | Subject: &v1.SubjectReference{ 78 | Object: &v1.ObjectReference{ 79 | ObjectId: "john_doe", 80 | ObjectType: "user", 81 | }, 82 | }, 83 | }) 84 | if err != nil { 85 | log.Fatal("unable to issue PermissionCheck: %w", err) 86 | } 87 | 88 | log.Printf("check result: %s", checkResp.Permissionship.String()) 89 | } 90 | 91 | func newServer(ctx context.Context) (server.RunnableServer, error) { 92 | ds, err := datastore.NewDatastore(ctx, 93 | datastore.DefaultDatastoreConfig().ToOption(), 94 | datastore.WithRequestHedgingEnabled(false), 95 | ) 96 | if err != nil { 97 | log.Fatalf("unable to start memdb datastore: %s", err) 98 | } 99 | 100 | configOpts := []server.ConfigOption{ 101 | server.WithGRPCServer(util.GRPCServerConfig{ 102 | Network: util.BufferedNetwork, 103 | Enabled: true, 104 | }), 105 | server.WithGRPCAuthFunc(func(ctx context.Context) (context.Context, error) { 106 | return ctx, nil 107 | }), 108 | server.WithHTTPGateway(util.HTTPServerConfig{HTTPEnabled: false}), 109 | server.WithMetricsAPI(util.HTTPServerConfig{HTTPEnabled: true}), 110 | // disable caching since it's all in memory 111 | server.WithDispatchCacheConfig(server.CacheConfig{Enabled: false, Metrics: false}), 112 | server.WithNamespaceCacheConfig(server.CacheConfig{Enabled: false, Metrics: false}), 113 | server.WithClusterDispatchCacheConfig(server.CacheConfig{Enabled: false, Metrics: false}), 114 | server.WithDatastore(ds), 115 | } 116 | 117 | return server.NewConfigWithOptionsAndDefaults(configOpts...).Complete(ctx) 118 | } 119 | -------------------------------------------------------------------------------- /tracing/README.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | This docker compose sets up SpiceDB with an open-telemetry based stack for tracing (OTEL Collector, Tempo and Grafana). 4 | This is for demonstration purposes and not meant to be used as a production observability setup. 5 | 6 | - SpiceDB is configured to send OTEL traces to an instance of the otel-collector 7 | - otel-collector exports traces to tempo, the latter acting as tracing backend 8 | - grafana is configured with tempo as datasource 9 | 10 | ## Usage 11 | 12 | ```shell 13 | docker compose up 14 | ``` 15 | 16 | Grafana will be available locally at http://localhost:3000 with Tempo set up as datasource for tracing. 17 | 18 | Issue some requests to spicedb so we can start collecting traces 19 | 20 | ```bash 21 | zed context set example localhost:50051 foobar --insecure 22 | zed schema write schema.zed 23 | zed schema read 24 | zed relationship create document:1 writer user:1 25 | zed permission check document:1 view user:1 26 | ``` 27 | -------------------------------------------------------------------------------- /tracing/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "3" 3 | 4 | services: 5 | spicedb: 6 | image: "authzed/spicedb" 7 | command: "serve" 8 | restart: "always" 9 | ports: 10 | - "9090" # prometheus metrics 11 | - "50051:50051" # grpc endpoint 12 | environment: 13 | - "SPICEDB_LOG_FORMAT=console" 14 | - "SPICEDB_GRPC_PRESHARED_KEY=foobar" 15 | - "SPICEDB_DATASTORE_ENGINE=memory" 16 | - "SPICEDB_DISPATCH_CACHE_METRICS=true" 17 | - "SPICEDB_DISPATCH_CLUSTER_METRICS=true" 18 | - "SPICEDB_NS_CACHE_METRICS=true" 19 | - "SPICEDB_METRICS_ENABLED=true" 20 | - "SPICEDB_OTEL_PROVIDER=otlpgrpc" 21 | - "SPICEDB_OTEL_SAMPLE_RATIO=1" 22 | - "OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317" 23 | depends_on: 24 | - "otel-collector" 25 | otel-collector: 26 | image: "otel/opentelemetry-collector:0.60.0" 27 | command: "--config /etc/otel-config.yaml" 28 | volumes: 29 | - "./otel-config.yaml:/etc/otel-config.yaml" 30 | ports: 31 | - "4317:4317" # OTLP gRPC 32 | - "8888" # Prometheus metrics for collector 33 | depends_on: 34 | - "tempo" 35 | tempo: 36 | image: "grafana/tempo:1.5.0" 37 | command: "-search.enabled=true -config.file=/etc/tempo.yaml" 38 | volumes: 39 | - "./tempo.yaml:/etc/tempo.yaml" 40 | restart: "unless-stopped" 41 | ports: 42 | - "4317" # OTLP gRPC 43 | - "3100" # tempo 44 | grafana: 45 | image: "grafana/grafana:9.1.5-ubuntu" 46 | volumes: 47 | - "./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml" 48 | environment: 49 | - "GF_AUTH_ANONYMOUS_ENABLED=true" 50 | - "GF_AUTH_ANONYMOUS_ORG_ROLE=Admin" 51 | - "GF_AUTH_DISABLE_LOGIN_FORM=true" 52 | ports: 53 | - "3000:3000" 54 | depends_on: 55 | - "tempo" 56 | -------------------------------------------------------------------------------- /tracing/grafana-datasources.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: 1 3 | 4 | datasources: 5 | - name: "Tempo" 6 | type: "tempo" 7 | access: "proxy" 8 | orgId: 1 9 | url: "http://tempo:3100" 10 | basicAuth: false 11 | isDefault: true 12 | version: 1 13 | editable: true 14 | apiVersion: 1 15 | uid: "tempo" 16 | -------------------------------------------------------------------------------- /tracing/otel-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | receivers: 3 | otlp: 4 | protocols: 5 | grpc: 6 | endpoint: "0.0.0.0:4317" 7 | 8 | processors: 9 | batch: 10 | 11 | exporters: 12 | logging: 13 | loglevel: "debug" 14 | otlp: 15 | endpoint: "tempo:4317" 16 | compression: "none" 17 | tls: 18 | insecure: true 19 | 20 | service: 21 | pipelines: 22 | traces: 23 | receivers: ["otlp"] 24 | processors: ["batch"] 25 | exporters: ["otlp"] 26 | telemetry: 27 | logs: 28 | level: "info" 29 | metrics: 30 | address: ":8888" 31 | -------------------------------------------------------------------------------- /tracing/schema.zed: -------------------------------------------------------------------------------- 1 | definition user {} 2 | 3 | definition document { 4 | relation writer: user 5 | relation reader: user 6 | 7 | permission edit = writer 8 | permission view = reader + edit 9 | } -------------------------------------------------------------------------------- /tracing/tempo.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | auth_enabled: false 3 | 4 | server: 5 | http_listen_port: 3100 6 | 7 | distributor: 8 | receivers: 9 | otlp: 10 | protocols: 11 | http: 12 | grpc: 13 | 14 | ingester: 15 | trace_idle_period: "10s" 16 | max_block_bytes: 100_000 17 | max_block_duration: "1m" 18 | 19 | compactor: 20 | compaction: 21 | compaction_window: "1h" 22 | max_block_bytes: 100_000_000 23 | block_retention: "1h" 24 | compacted_block_retention: "10m" 25 | 26 | storage: 27 | trace: 28 | backend: "local" 29 | block: 30 | bloom_filter_false_positive: .05 31 | index_downsample_bytes: 1000 32 | encoding: "zstd" 33 | wal: 34 | path: "/tmp/tempo/wal" 35 | encoding: "snappy" 36 | local: 37 | path: "/tmp/tempo/blocks" 38 | pool: 39 | max_workers: 100 40 | queue_depth: 10000 41 | --------------------------------------------------------------------------------