├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── automatic-api-update.yaml │ ├── cla.yaml │ ├── lint.yaml │ ├── manual-api-update.yaml │ ├── publish-to-pypi.yml │ └── test.yaml ├── .gitignore ├── .yamllint ├── CODE-OF-CONDUCT.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── DCO ├── LICENSE ├── README.md ├── authzed ├── api │ ├── materialize │ │ └── v0 │ │ │ ├── watchpermissions_pb2.py │ │ │ ├── watchpermissions_pb2.pyi │ │ │ ├── watchpermissions_pb2_grpc.py │ │ │ ├── watchpermissions_pb2_grpc.pyi │ │ │ ├── watchpermissionsets_pb2.py │ │ │ ├── watchpermissionsets_pb2.pyi │ │ │ ├── watchpermissionsets_pb2_grpc.py │ │ │ └── watchpermissionsets_pb2_grpc.pyi │ ├── v0 │ │ ├── core_pb2.py │ │ ├── core_pb2.pyi │ │ ├── core_pb2_grpc.py │ │ ├── core_pb2_grpc.pyi │ │ ├── developer_pb2.py │ │ ├── developer_pb2.pyi │ │ ├── developer_pb2_grpc.py │ │ └── developer_pb2_grpc.pyi │ ├── v1 │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── core_pb2.py │ │ ├── core_pb2.pyi │ │ ├── core_pb2_grpc.py │ │ ├── core_pb2_grpc.pyi │ │ ├── debug_pb2.py │ │ ├── debug_pb2.pyi │ │ ├── debug_pb2_grpc.py │ │ ├── debug_pb2_grpc.pyi │ │ ├── error_reason_pb2.py │ │ ├── error_reason_pb2.pyi │ │ ├── error_reason_pb2_grpc.py │ │ ├── error_reason_pb2_grpc.pyi │ │ ├── experimental_service_pb2.py │ │ ├── experimental_service_pb2.pyi │ │ ├── experimental_service_pb2_grpc.py │ │ ├── experimental_service_pb2_grpc.pyi │ │ ├── openapi_pb2.py │ │ ├── openapi_pb2.pyi │ │ ├── openapi_pb2_grpc.py │ │ ├── openapi_pb2_grpc.pyi │ │ ├── permission_service_pb2.py │ │ ├── permission_service_pb2.pyi │ │ ├── permission_service_pb2_grpc.py │ │ ├── permission_service_pb2_grpc.pyi │ │ ├── schema_service_pb2.py │ │ ├── schema_service_pb2.pyi │ │ ├── schema_service_pb2_grpc.py │ │ ├── schema_service_pb2_grpc.pyi │ │ ├── watch_service_pb2.py │ │ ├── watch_service_pb2.pyi │ │ ├── watch_service_pb2_grpc.py │ │ └── watch_service_pb2_grpc.pyi │ └── v1alpha1 │ │ ├── schema_pb2.py │ │ ├── schema_pb2.pyi │ │ ├── schema_pb2_grpc.py │ │ ├── schema_pb2_grpc.pyi │ │ ├── watchresources_service_pb2.py │ │ ├── watchresources_service_pb2.pyi │ │ ├── watchresources_service_pb2_grpc.py │ │ └── watchresources_service_pb2_grpc.pyi └── py.typed ├── buf.gen.yaml ├── buf └── validate │ ├── validate_pb2.py │ └── validate_pb2.pyi ├── examples ├── v1 │ ├── bulk_check_permissions.py │ ├── bulk_import_export_relationships.py │ ├── check_permissions.py │ ├── import_bulk_relationships.py │ ├── read_schema.py │ ├── write_relationships.py │ └── write_schemas.py └── v1alpha1 │ ├── read_schema.py │ └── read_schema_async.py ├── google ├── api │ ├── annotations_pb2.py │ ├── annotations_pb2.pyi │ ├── http_pb2.py │ └── http_pb2.pyi └── rpc │ ├── status_pb2.py │ └── status_pb2.pyi ├── grpcutil └── __init__.py ├── poetry.lock ├── protoc_gen_openapiv2 └── options │ ├── annotations_pb2.py │ ├── annotations_pb2.pyi │ ├── openapiv2_pb2.py │ └── openapiv2_pb2.pyi ├── pyproject.toml ├── tests ├── __init__.py ├── calls.py ├── conftest.py ├── insecure_client_test.py ├── misc_test.py ├── utils.py └── v1_test.py └── validate ├── validate_pb2.py └── validate_pb2.pyi /.gitattributes: -------------------------------------------------------------------------------- 1 | # generated protobufs 2 | *pb2.py -diff linguist-generated=true 3 | *pb2.pyi -diff linguist-generated=true 4 | *pb2_grpc.py -diff linguist-generated=true 5 | *pb2_grpc.pyi -diff linguist-generated=true 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: "pip" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | labels: 9 | - "area/dependencies" 10 | groups: 11 | pip: 12 | patterns: ["*"] 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "weekly" 17 | groups: 18 | github-actions: 19 | patterns: ["*"] 20 | -------------------------------------------------------------------------------- /.github/workflows/automatic-api-update.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Called update for API change" 3 | on: 4 | repository_dispatch: 5 | types: ["api_update"] 6 | jobs: 7 | test: 8 | name: "Create PR for API update" 9 | runs-on: "ubuntu-latest" 10 | steps: 11 | - uses: "actions/checkout@v4" 12 | - uses: "actions/setup-node@v4" 13 | - name: "Update Buf Script" 14 | id: "buf-update" 15 | uses: "authzed/actions/buf-api-update@main" 16 | with: 17 | api-commit: "${{ github.event.client_payload.BUFTAG }}" 18 | spec-path: "buf.gen.yaml" 19 | file-format: "buf-gen-yaml" 20 | - name: "Output update status" 21 | env: 22 | UPDATED_STATUS: "${{ steps.buf-update.outputs.updated }}" 23 | run: | 24 | echo "Update status: $UPDATED_STATUS" 25 | - name: "Install buf" 26 | uses: "bufbuild/buf-setup-action@v1.50.0" 27 | with: 28 | github_token: "${{ secrets.GITHUB_TOKEN }}" 29 | if: "steps.buf-update.outputs.updated == 'true'" 30 | - name: "Run buf generate" 31 | if: "steps.buf-update.outputs.updated == 'true'" 32 | run: "buf generate" 33 | - name: "Create Pull Request" 34 | uses: "peter-evans/create-pull-request@v7.0.8" 35 | if: "steps.buf-update.outputs.updated == 'true'" 36 | with: 37 | delete-branch: "true" 38 | # https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs 39 | # This is how we ensure that workflows run 40 | draft: "always-true" 41 | title: "Update API to ${{ github.event.client_payload.BUFTAG }}" 42 | branch: "api-change/${{ github.event.client_payload.BUFTAG }}" 43 | base: "main" 44 | token: "${{ secrets.GITHUB_TOKEN }}" 45 | -------------------------------------------------------------------------------- /.github/workflows/cla.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "CLA" 3 | on: 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: "Format & Lint" 12 | runs-on: "ubuntu-latest" 13 | strategy: 14 | matrix: 15 | python-version: 16 | - "3.10" 17 | fail-fast: false 18 | steps: 19 | - uses: "actions/checkout@v4" 20 | - uses: "bewuethr/yamllint-action@v1.3.0" 21 | with: 22 | config-file: ".yamllint" 23 | - uses: "actions/setup-python@v5" 24 | with: 25 | python-version: "3.10" 26 | - name: "Setup Python Environment" 27 | run: "pip install -U pip virtualenv" 28 | - name: "Install Dependencies" 29 | run: | 30 | virtualenv ~/.cache/virtualenv/authzedpy 31 | source ~/.cache/virtualenv/authzedpy/bin/activate 32 | pip install poetry 33 | poetry env info 34 | poetry install --only dev 35 | - name: "Pyflakes" 36 | run: | 37 | source ~/.cache/virtualenv/authzedpy/bin/activate 38 | find . -name "*.py" | grep -v "_pb2" | xargs pyflakes 39 | - name: "Blacken" 40 | run: | 41 | source ~/.cache/virtualenv/authzedpy/bin/activate 42 | black --check --diff . 43 | - name: "Isort" 44 | run: | 45 | source ~/.cache/virtualenv/authzedpy/bin/activate 46 | find . -name "*.py" | grep -v "_pb2" | xargs isort --check --diff 47 | codeql: 48 | name: "Analyze with CodeQL" 49 | runs-on: "ubuntu-latest" 50 | permissions: 51 | actions: "read" 52 | contents: "read" 53 | security-events: "write" 54 | strategy: 55 | fail-fast: false 56 | matrix: 57 | language: ["python"] 58 | steps: 59 | - uses: "actions/checkout@v4" 60 | - uses: "authzed/actions/codeql@main" 61 | trivy: 62 | name: "Analyze with Trivy" 63 | runs-on: "ubuntu-latest" 64 | steps: 65 | - uses: "actions/checkout@v4" 66 | - name: "Run Trivy vulnerability scanner" 67 | uses: "aquasecurity/trivy-action@master" 68 | with: 69 | scan-type: "fs" 70 | ignore-unfixed: true 71 | format: "sarif" 72 | output: "trivy-results.sarif" 73 | severity: "CRITICAL" 74 | env: 75 | TRIVY_DB_REPOSITORY: "public.ecr.aws/aquasecurity/trivy-db" 76 | TRIVY_JAVA_DB_REPOSITORY: "public.ecr.aws/aquasecurity/trivy-java-db" 77 | - name: "Upload Trivy scan results to GitHub Security tab" 78 | uses: "github/codeql-action/upload-sarif@v3" 79 | with: 80 | sarif_file: "trivy-results.sarif" 81 | mypy: 82 | name: "Type Check with Mypy" 83 | runs-on: "ubuntu-latest" 84 | steps: 85 | - uses: "actions/checkout@v4" 86 | - uses: "actions/setup-python@v5" 87 | with: 88 | python-version: "3.10" 89 | - name: "Setup Python Environment" 90 | run: "pip install -U pip virtualenv" 91 | - name: "Install Dependencies" 92 | run: | 93 | virtualenv ~/.cache/virtualenv/authzedpy 94 | source ~/.cache/virtualenv/authzedpy/bin/activate 95 | pip install poetry 96 | poetry env info 97 | poetry install --only dev 98 | - name: "mypy" 99 | run: | 100 | source ~/.cache/virtualenv/authzedpy/bin/activate 101 | mypy authzed 102 | -------------------------------------------------------------------------------- /.github/workflows/manual-api-update.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Update for API change" 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | buftag: 7 | description: "Tag or commit from https://buf.build/authzed/api/tags/main" 8 | required: true 9 | type: "string" 10 | jobs: 11 | test: 12 | name: "Create PR for API update" 13 | runs-on: "ubuntu-latest" 14 | steps: 15 | - uses: "actions/checkout@v4" 16 | - uses: "actions/setup-node@v4" 17 | - name: "Update Buf Script" 18 | id: "buf-update" 19 | uses: "authzed/actions/buf-api-update@main" 20 | with: 21 | api-commit: "${{ inputs.buftag }}" 22 | spec-path: "buf.gen.yaml" 23 | file-format: "buf-gen-yaml" 24 | - name: "Output update status" 25 | env: 26 | UPDATED_STATUS: "${{ steps.buf-update.outputs.updated }}" 27 | run: | 28 | echo "Update status: $UPDATED_STATUS" 29 | - name: "Install buf" 30 | uses: "bufbuild/buf-setup-action@v1.50.0" 31 | with: 32 | github_token: "${{ secrets.GITHUB_TOKEN }}" 33 | if: "steps.buf-update.outputs.updated == 'true'" 34 | - name: "Run buf generate" 35 | if: "steps.buf-update.outputs.updated == 'true'" 36 | run: "buf generate" 37 | - name: "Create Pull Request" 38 | uses: "peter-evans/create-pull-request@v7.0.8" 39 | if: "steps.buf-update.outputs.updated == 'true'" 40 | with: 41 | delete-branch: "true" 42 | # https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs 43 | # This is how we ensure that workflows run 44 | draft: "always-true" 45 | title: "Update API to ${{ inputs.buftag }}" 46 | base: "main" 47 | branch: "api-change/${{ inputs.buftag }}" 48 | token: "${{ secrets.GITHUB_TOKEN }}" 49 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-pypi.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Publish to PyPI" 3 | on: 4 | release: 5 | types: 6 | - "published" 7 | jobs: 8 | publish: 9 | name: "Build & Publish" 10 | runs-on: "ubuntu-latest" 11 | steps: 12 | - uses: "actions/checkout@v4" 13 | - name: "Install Poetry" 14 | uses: "snok/install-poetry@v1" 15 | - uses: "actions/setup-python@v5" 16 | with: 17 | python-version: "3.11" 18 | cache: 'poetry' 19 | # This gives us a version number without the release prefix 20 | - name: "Write release version" 21 | run: | 22 | VERSION=${GITHUB_REF_NAME#v} 23 | echo Version: $VERSION 24 | echo "VERSION=$VERSION" >> $GITHUB_ENV 25 | - name: "Set the release number in pyproject.toml" 26 | run: "poetry version -s $VERSION" 27 | - name: "Build wheel and source tarball" 28 | run: "poetry build" 29 | - name: "Publish" 30 | uses: "pypa/gh-action-pypi-publish@release/v1" 31 | with: 32 | password: "${{ secrets.PYPI_API_TOKEN }}" 33 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Test" 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | pull_request: 8 | branches: ["*"] 9 | env: 10 | GRPC_VERSION: "1.68" 11 | BUF_VERSION: "1.30.0" 12 | jobs: 13 | pytest: 14 | name: "Unit and Integration Tests" 15 | runs-on: "ubuntu-latest" 16 | strategy: 17 | matrix: 18 | python-version: 19 | - "3.9" 20 | - "3.10" 21 | - "3.11" 22 | - "3.12" 23 | - "3.13" 24 | steps: 25 | - uses: "actions/checkout@v4" 26 | - uses: "actions/setup-python@v5" 27 | with: 28 | python-version: "${{ matrix.python-version }}" 29 | - name: "Setup Python Environment" 30 | run: "pip install -U pip virtualenv" 31 | - name: "Install Dependencies" 32 | run: | 33 | virtualenv ~/.cache/virtualenv/authzedpy 34 | source ~/.cache/virtualenv/authzedpy/bin/activate 35 | pip install poetry 36 | poetry env info 37 | poetry install 38 | - uses: "authzed/action-spicedb@v1" 39 | with: 40 | version: "latest" 41 | - name: "Pytest" 42 | run: | 43 | source ~/.cache/virtualenv/authzedpy/bin/activate 44 | pytest -vv 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /.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 | 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. 2 | 3 | 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. 4 | 5 | Examples of unacceptable behavior by participants include: 6 | 7 | - The use of sexualized language or imagery 8 | - Personal attacks 9 | - Trolling or insulting/derogatory comments 10 | - Public or private harassment 11 | - Publishing other’s private information, such as physical or electronic addresses, without explicit permission 12 | - Other unethical or unprofessional conduct 13 | 14 | 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. 15 | By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. 16 | Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the Contributor Covenant, version 1.2.0, available at https://www.contributor-covenant.org/version/1/2/0/code-of-conduct.html 23 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @authzed/spicedb-maintainers 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ## Communication 4 | 5 | - Issues: [GitHub](https://github.com/authzed/authzed-py/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 | Deuplicate 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 branch from where to base the contribution -- this is almost always `main` 45 | - Push changes into a branch of your fork 46 | - Submit a pull request 47 | - Respond to feedback from project maintainers 48 | 49 | Creating new issues is one of the best ways to contribute. 50 | You have no obligation to offer a solution or code to fix an issue that you open. 51 | 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. 52 | 53 | ## Legal requirements 54 | 55 | In order to protect both you and ourselves, all commits will require an explicit sign-off that acknowledges the [DCO]. 56 | 57 | Sign-off commits end with the following line: 58 | 59 | ``` 60 | Signed-off-by: Random J Developer 61 | ``` 62 | 63 | This can be done by using the `--signoff` (or `-s` for short) git flag to append this automatically to your commit message. 64 | 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. 65 | 66 | [DCO]: /DCO 67 | 68 | ## Common tasks 69 | 70 | ### Adding and updating dependencies 71 | 72 | This project uses [Poetry] for managing dependencies. 73 | By default, Poetry will create a [virtualenv] for you. 74 | Optionally, we recommend using [pyenv] if you need to manage Python versions as well as virtualenvs. 75 | 76 | Adding a new dependency can be done with `poetry add` command: 77 | 78 | ```sh 79 | poetry add library 80 | ``` 81 | 82 | Updating all dependencies can be done with `poetry update` command: 83 | 84 | ```sh 85 | poetry update 86 | ``` 87 | 88 | For more instructions, see the [Poetry documentation]. 89 | 90 | [poetry]: https://python-poetry.org 91 | [virtualenv]: https://virtualenv.pypa.io/en/latest/ 92 | [pyenv]: https://github.com/pyenv/pyenv 93 | [poetry documentation]: https://python-poetry.org/docs/cli 94 | 95 | ### Updating generated Protobuf code 96 | 97 | All [Protobuf] code is managed using [buf]. 98 | The [shebang] at the top of `buf.gen.yaml` contains the [Buf Registry ref] that will be generated. 99 | You can regenerate the code by executing `buf.gen.yaml`: 100 | 101 | [Protobuf]: https://developers.google.com/protocol-buffers/ 102 | [buf]: https://docs.buf.build/installation 103 | [shebang]: https://en.wikipedia.org/wiki/Shebang_(Unix) 104 | [Buf Registry ref]: https://buf.build/authzed/api/history 105 | 106 | ```sh 107 | ./buf.gen.yaml 108 | ``` 109 | 110 | ### Running the Unit tests 111 | 112 | 1. `poetry install --with dev` 113 | 1. `docker run -d -p 50051:50051 -p 50052:50052 --entrypoint spicedb quay.io/authzed/spicedb:latest-debug serve-testing` (or pick a specific version of the spicedb server as appropriate) 114 | 1. `poetry run pytest -vv .` 115 | 116 | ### Passing the linters 117 | 118 | See the [lint workflow](/.github/workflows/lint.yaml) for updated steps, but it should look something like this: 119 | 120 | ```sh 121 | poetry install --with dev 122 | poetry shell 123 | find . -name "*.py" | grep -v "_pb2" | xargs pyflakes 124 | black . 125 | find . -name "*.py" | grep -v "_pb2" | xargs isort 126 | ``` 127 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Authzed Python Client 2 | 3 | [![PyPI](https://img.shields.io/pypi/v/authzed?color=%23006dad)](https://pypi.org/project/authzed) 4 | [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) 5 | [![Build Status](https://github.com/authzed/authzed-py/workflows/Test/badge.svg)](https://github.com/authzed/authzed-py/actions) 6 | [![Mailing List](https://img.shields.io/badge/email-google%20groups-4285F4)](https://groups.google.com/g/authzed-oss) 7 | [![Discord Server](https://img.shields.io/discord/844600078504951838?color=7289da&logo=discord "Discord Server")](https://discord.gg/jTysUaxXzM) 8 | [![Twitter](https://img.shields.io/twitter/follow/authzed?color=%23179CF0&logo=twitter&style=flat-square)](https://twitter.com/authzed) 9 | 10 | This repository houses the Python client library for Authzed. 11 | 12 | [Authzed] is a database and service that stores, computes, and validates your application's permissions. 13 | 14 | Developers create a schema that models their permissions requirements and use a client library, such as this one, to apply the schema to the database, insert data into the database, and query the data to efficiently check permissions in their applications. 15 | 16 | Supported client API versions: 17 | 18 | - [v1](https://docs.authzed.com/reference/api#authzedapiv1) 19 | 20 | You can find more info on each API on the [Authzed API reference documentation]. 21 | Additionally, Protobuf API documentation can be found on the [Buf Registry Authzed API repository]. 22 | 23 | See [CONTRIBUTING.md] for instructions on how to contribute and perform common tasks like building the project and running tests. 24 | 25 | [Authzed]: https://authzed.com 26 | [Authzed API Reference documentation]: https://docs.authzed.com/reference/api 27 | [Buf Registry Authzed API repository]: https://buf.build/authzed/api/docs/main 28 | [CONTRIBUTING.md]: CONTRIBUTING.md 29 | 30 | ## Getting Started 31 | 32 | We highly recommend following the **[Protecting Your First App]** guide to learn the latest best practice to integrate an application with Authzed. 33 | 34 | If you're interested in examples of a specific version of the API, they can be found in their respective folders in the [examples directory]. 35 | 36 | [Protecting Your First App]: https://docs.authzed.com/guides/first-app 37 | [examples directory]: /examples 38 | 39 | ## Basic Usage 40 | 41 | ### Installation 42 | 43 | This project is packaged as the wheel `authzed` on the [Python Package Index]. 44 | 45 | If you are using [pip], the command to install the library is: 46 | 47 | ```sh 48 | pip install authzed 49 | ``` 50 | 51 | [Python Package Index]: https://pypi.org/project/authzed 52 | [pip]: https://pip.pypa.io 53 | 54 | ### Initializing a client 55 | 56 | With the exception of [gRPC] utility functions found in `grpcutil`, everything required to connect and make API calls is located in a module respective to API version. 57 | 58 | In order to successfully connect, you will have to provide a [Bearer Token] with your own API Token from the [Authzed dashboard] in place of `t_your_token_here_1234567deadbeef` in the following example: 59 | 60 | [grpc]: https://grpc.io 61 | [Bearer Token]: https://datatracker.ietf.org/doc/html/rfc6750#section-2.1 62 | [Authzed Dashboard]: https://app.authzed.com 63 | 64 | ```py 65 | from authzed.api.v1 import Client 66 | from grpcutil import bearer_token_credentials 67 | 68 | 69 | client = Client( 70 | "grpc.authzed.com:443", 71 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 72 | ) 73 | ``` 74 | 75 | ### Performing an API call 76 | 77 | ```py 78 | from authzed.api.v1 import ( 79 | CheckPermissionRequest, 80 | CheckPermissionResponse, 81 | ObjectReference, 82 | SubjectReference, 83 | ) 84 | 85 | 86 | post_one = ObjectReference(object_type="blog/post", object_id="1") 87 | emilia = SubjectReference(object=ObjectReference( 88 | object_type="blog/user", 89 | object_id="emilia", 90 | )) 91 | 92 | # Is Emilia in the set of users that can read post #1? 93 | resp = client.CheckPermission(CheckPermissionRequest( 94 | resource=post_one, 95 | permission="reader", 96 | subject=emilia, 97 | )) 98 | assert resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 99 | ``` 100 | 101 | ### Insecure Client Usage 102 | When running in a context like `docker compose`, because of Docker's virtual networking, 103 | the gRPC client sees the SpiceDB container as "remote." It has built-in safeguards to prevent 104 | calling a remote client in an insecure manner, such as using client credentials without TLS. 105 | 106 | However, this is a pain when setting up a development or testing environment, so we provide 107 | the `InsecureClient` as a convenience: 108 | 109 | ```py 110 | from authzed.api.v1 import InsecureClient 111 | 112 | client = InsecureClient( 113 | "spicedb:50051", 114 | "my super secret token" 115 | ) 116 | ``` 117 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissions_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/materialize/v0/watchpermissions.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/materialize/v0/watchpermissions.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v1 import core_pb2 as authzed_dot_api_dot_v1_dot_core__pb2 26 | 27 | 28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1authzed/api/materialize/v0/watchpermissions.proto\x12\x1a\x61uthzed.api.materialize.v0\x1a\x19\x61uthzed/api/v1/core.proto\"\xbc\x01\n\x17WatchPermissionsRequest\x12O\n\x0bpermissions\x18\x01 \x03(\x0b\x32-.authzed.api.materialize.v0.WatchedPermissionR\x0bpermissions\x12P\n\x17optional_starting_after\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x15optionalStartingAfter\"\xb7\x01\n\x11WatchedPermission\x12#\n\rresource_type\x18\x01 \x01(\tR\x0cresourceType\x12\x1e\n\npermission\x18\x02 \x01(\tR\npermission\x12!\n\x0csubject_type\x18\x03 \x01(\tR\x0bsubjectType\x12:\n\x19optional_subject_relation\x18\x04 \x01(\tR\x17optionalSubjectRelation\"\xb9\x01\n\x18WatchPermissionsResponse\x12\x46\n\x06\x63hange\x18\x01 \x01(\x0b\x32,.authzed.api.materialize.v0.PermissionChangeH\x00R\x06\x63hange\x12I\n\x12\x63ompleted_revision\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenH\x00R\x11\x63ompletedRevisionB\n\n\x08response\"\xe9\x03\n\x10PermissionChange\x12\x34\n\x08revision\x18\x01 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x08revision\x12;\n\x08resource\x18\x02 \x01(\x0b\x32\x1f.authzed.api.v1.ObjectReferenceR\x08resource\x12\x1e\n\npermission\x18\x03 \x01(\tR\npermission\x12:\n\x07subject\x18\x04 \x01(\x0b\x32 .authzed.api.v1.SubjectReferenceR\x07subject\x12\x63\n\x0epermissionship\x18\x05 \x01(\x0e\x32;.authzed.api.materialize.v0.PermissionChange.PermissionshipR\x0epermissionship\"\xa0\x01\n\x0ePermissionship\x12\x1e\n\x1aPERMISSIONSHIP_UNSPECIFIED\x10\x00\x12 \n\x1cPERMISSIONSHIP_NO_PERMISSION\x10\x01\x12!\n\x1dPERMISSIONSHIP_HAS_PERMISSION\x10\x02\x12)\n%PERMISSIONSHIP_CONDITIONAL_PERMISSION\x10\x03\x32\x9d\x01\n\x17WatchPermissionsService\x12\x81\x01\n\x10WatchPermissions\x12\x33.authzed.api.materialize.v0.WatchPermissionsRequest\x1a\x34.authzed.api.materialize.v0.WatchPermissionsResponse\"\x00\x30\x01\x42\x62\n\x1e\x63om.authzed.api.materialize.v0P\x01Z>github.com/authzed/authzed-go/proto/authzed/api/materialize/v0b\x06proto3') 29 | 30 | _globals = globals() 31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.materialize.v0.watchpermissions_pb2', _globals) 33 | if not _descriptor._USE_C_DESCRIPTORS: 34 | _globals['DESCRIPTOR']._loaded_options = None 35 | _globals['DESCRIPTOR']._serialized_options = b'\n\036com.authzed.api.materialize.v0P\001Z>github.com/authzed/authzed-go/proto/authzed/api/materialize/v0' 36 | _globals['_WATCHPERMISSIONSREQUEST']._serialized_start=109 37 | _globals['_WATCHPERMISSIONSREQUEST']._serialized_end=297 38 | _globals['_WATCHEDPERMISSION']._serialized_start=300 39 | _globals['_WATCHEDPERMISSION']._serialized_end=483 40 | _globals['_WATCHPERMISSIONSRESPONSE']._serialized_start=486 41 | _globals['_WATCHPERMISSIONSRESPONSE']._serialized_end=671 42 | _globals['_PERMISSIONCHANGE']._serialized_start=674 43 | _globals['_PERMISSIONCHANGE']._serialized_end=1163 44 | _globals['_PERMISSIONCHANGE_PERMISSIONSHIP']._serialized_start=1003 45 | _globals['_PERMISSIONCHANGE_PERMISSIONSHIP']._serialized_end=1163 46 | _globals['_WATCHPERMISSIONSSERVICE']._serialized_start=1166 47 | _globals['_WATCHPERMISSIONSSERVICE']._serialized_end=1323 48 | # @@protoc_insertion_point(module_scope) 49 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissions_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import authzed.api.v1.core_pb2 7 | import builtins 8 | import collections.abc 9 | import google.protobuf.descriptor 10 | import google.protobuf.internal.containers 11 | import google.protobuf.internal.enum_type_wrapper 12 | import google.protobuf.message 13 | import sys 14 | import typing 15 | 16 | if sys.version_info >= (3, 10): 17 | import typing as typing_extensions 18 | else: 19 | import typing_extensions 20 | 21 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 22 | 23 | @typing.final 24 | class WatchPermissionsRequest(google.protobuf.message.Message): 25 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 26 | 27 | PERMISSIONS_FIELD_NUMBER: builtins.int 28 | OPTIONAL_STARTING_AFTER_FIELD_NUMBER: builtins.int 29 | @property 30 | def permissions(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___WatchedPermission]: 31 | """permissions is a list of permissions to watch for changes. At least one permission must be specified, and it must 32 | be a subset or equal to the permissions that were enabled for the service. 33 | """ 34 | 35 | @property 36 | def optional_starting_after(self) -> authzed.api.v1.core_pb2.ZedToken: 37 | """optional_starting_after is the revision token to start watching from. If not provided, the stream 38 | will start from the current revision at the moment of the request. 39 | """ 40 | 41 | def __init__( 42 | self, 43 | *, 44 | permissions: collections.abc.Iterable[global___WatchedPermission] | None = ..., 45 | optional_starting_after: authzed.api.v1.core_pb2.ZedToken | None = ..., 46 | ) -> None: ... 47 | def HasField(self, field_name: typing.Literal["optional_starting_after", b"optional_starting_after"]) -> builtins.bool: ... 48 | def ClearField(self, field_name: typing.Literal["optional_starting_after", b"optional_starting_after", "permissions", b"permissions"]) -> None: ... 49 | 50 | global___WatchPermissionsRequest = WatchPermissionsRequest 51 | 52 | @typing.final 53 | class WatchedPermission(google.protobuf.message.Message): 54 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 55 | 56 | RESOURCE_TYPE_FIELD_NUMBER: builtins.int 57 | PERMISSION_FIELD_NUMBER: builtins.int 58 | SUBJECT_TYPE_FIELD_NUMBER: builtins.int 59 | OPTIONAL_SUBJECT_RELATION_FIELD_NUMBER: builtins.int 60 | resource_type: builtins.str 61 | """resource_type is the type of the resource to watch for changes.""" 62 | permission: builtins.str 63 | """permission is the permission to watch for changes.""" 64 | subject_type: builtins.str 65 | """subject_type is the type of the subject to watch for changes.""" 66 | optional_subject_relation: builtins.str 67 | """optional_subject_relation is the relation on the subject to watch for changes.""" 68 | def __init__( 69 | self, 70 | *, 71 | resource_type: builtins.str = ..., 72 | permission: builtins.str = ..., 73 | subject_type: builtins.str = ..., 74 | optional_subject_relation: builtins.str = ..., 75 | ) -> None: ... 76 | def ClearField(self, field_name: typing.Literal["optional_subject_relation", b"optional_subject_relation", "permission", b"permission", "resource_type", b"resource_type", "subject_type", b"subject_type"]) -> None: ... 77 | 78 | global___WatchedPermission = WatchedPermission 79 | 80 | @typing.final 81 | class WatchPermissionsResponse(google.protobuf.message.Message): 82 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 83 | 84 | CHANGE_FIELD_NUMBER: builtins.int 85 | COMPLETED_REVISION_FIELD_NUMBER: builtins.int 86 | @property 87 | def change(self) -> global___PermissionChange: 88 | """change is the computed permission delta that has occurred as result of a mutation in origin SpiceDB. 89 | The consumer should apply this change to the current state of the computed permissions in their target system. 90 | Once an event arrives with completed_revision instead, the consumer shall consider there are not more changes 91 | originating from that revision. 92 | 93 | The consumer should keep track of the revision in order to resume streaming in the event of consumer restarts. 94 | """ 95 | 96 | @property 97 | def completed_revision(self) -> authzed.api.v1.core_pb2.ZedToken: 98 | """completed_revision is the revision token that indicates all changes originating from a revision have been 99 | streamed and thus the revision should be considered completed. It may also be 100 | received without accompanying set of changes, indicating that a mutation in the origin SpiceDB cluster did 101 | not yield any effective changes in the computed permissions 102 | """ 103 | 104 | def __init__( 105 | self, 106 | *, 107 | change: global___PermissionChange | None = ..., 108 | completed_revision: authzed.api.v1.core_pb2.ZedToken | None = ..., 109 | ) -> None: ... 110 | def HasField(self, field_name: typing.Literal["change", b"change", "completed_revision", b"completed_revision", "response", b"response"]) -> builtins.bool: ... 111 | def ClearField(self, field_name: typing.Literal["change", b"change", "completed_revision", b"completed_revision", "response", b"response"]) -> None: ... 112 | def WhichOneof(self, oneof_group: typing.Literal["response", b"response"]) -> typing.Literal["change", "completed_revision"] | None: ... 113 | 114 | global___WatchPermissionsResponse = WatchPermissionsResponse 115 | 116 | @typing.final 117 | class PermissionChange(google.protobuf.message.Message): 118 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 119 | 120 | class _Permissionship: 121 | ValueType = typing.NewType("ValueType", builtins.int) 122 | V: typing_extensions.TypeAlias = ValueType 123 | 124 | class _PermissionshipEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[PermissionChange._Permissionship.ValueType], builtins.type): 125 | DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor 126 | PERMISSIONSHIP_UNSPECIFIED: PermissionChange._Permissionship.ValueType # 0 127 | PERMISSIONSHIP_NO_PERMISSION: PermissionChange._Permissionship.ValueType # 1 128 | PERMISSIONSHIP_HAS_PERMISSION: PermissionChange._Permissionship.ValueType # 2 129 | PERMISSIONSHIP_CONDITIONAL_PERMISSION: PermissionChange._Permissionship.ValueType # 3 130 | 131 | class Permissionship(_Permissionship, metaclass=_PermissionshipEnumTypeWrapper): ... 132 | PERMISSIONSHIP_UNSPECIFIED: PermissionChange.Permissionship.ValueType # 0 133 | PERMISSIONSHIP_NO_PERMISSION: PermissionChange.Permissionship.ValueType # 1 134 | PERMISSIONSHIP_HAS_PERMISSION: PermissionChange.Permissionship.ValueType # 2 135 | PERMISSIONSHIP_CONDITIONAL_PERMISSION: PermissionChange.Permissionship.ValueType # 3 136 | 137 | REVISION_FIELD_NUMBER: builtins.int 138 | RESOURCE_FIELD_NUMBER: builtins.int 139 | PERMISSION_FIELD_NUMBER: builtins.int 140 | SUBJECT_FIELD_NUMBER: builtins.int 141 | PERMISSIONSHIP_FIELD_NUMBER: builtins.int 142 | permission: builtins.str 143 | """permission is the permission that has changed.""" 144 | permissionship: global___PermissionChange.Permissionship.ValueType 145 | """permissionship is the new permissionship of the subject over the resource after the change.""" 146 | @property 147 | def revision(self) -> authzed.api.v1.core_pb2.ZedToken: 148 | """revision represents the revision at which the change occurred.""" 149 | 150 | @property 151 | def resource(self) -> authzed.api.v1.core_pb2.ObjectReference: 152 | """resource is the resource that the permission change is related to.""" 153 | 154 | @property 155 | def subject(self) -> authzed.api.v1.core_pb2.SubjectReference: 156 | """subject is the subject that the permission change is related to.""" 157 | 158 | def __init__( 159 | self, 160 | *, 161 | revision: authzed.api.v1.core_pb2.ZedToken | None = ..., 162 | resource: authzed.api.v1.core_pb2.ObjectReference | None = ..., 163 | permission: builtins.str = ..., 164 | subject: authzed.api.v1.core_pb2.SubjectReference | None = ..., 165 | permissionship: global___PermissionChange.Permissionship.ValueType = ..., 166 | ) -> None: ... 167 | def HasField(self, field_name: typing.Literal["resource", b"resource", "revision", b"revision", "subject", b"subject"]) -> builtins.bool: ... 168 | def ClearField(self, field_name: typing.Literal["permission", b"permission", "permissionship", b"permissionship", "resource", b"resource", "revision", b"revision", "subject", b"subject"]) -> None: ... 169 | 170 | global___PermissionChange = PermissionChange 171 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissions_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | from authzed.api.materialize.v0 import watchpermissions_pb2 as authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2 6 | 7 | 8 | class WatchPermissionsServiceStub(object): 9 | """Missing associated documentation comment in .proto file.""" 10 | 11 | def __init__(self, channel): 12 | """Constructor. 13 | 14 | Args: 15 | channel: A grpc.Channel. 16 | """ 17 | self.WatchPermissions = channel.unary_stream( 18 | '/authzed.api.materialize.v0.WatchPermissionsService/WatchPermissions', 19 | request_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsRequest.SerializeToString, 20 | response_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsResponse.FromString, 21 | _registered_method=True) 22 | 23 | 24 | class WatchPermissionsServiceServicer(object): 25 | """Missing associated documentation comment in .proto file.""" 26 | 27 | def WatchPermissions(self, request, context): 28 | """WatchPermissions returns a stream of PermissionChange events for the given permissions. 29 | 30 | WatchPermissions is a long-running RPC, and will stream events until the client 31 | closes the connection or the server terminates the stream. The consumer is responsible of 32 | keeping track of the last seen revision and resuming the stream from that point in the event 33 | of disconnection or client-side restarts. 34 | 35 | The API does not offer a sharding mechanism and thus there should only be one consumer per target system. 36 | Implementing an active-active HA consumer setup over the same target system will require coordinating which 37 | revisions have been consumed in order to prevent transitioning to an inconsistent state. 38 | 39 | Usage of WatchPermissions requires to be explicitly enabled on the service, including the permissions to be 40 | watched. It requires more resources and is less performant than WatchPermissionsSets. It's usage 41 | is only recommended when performing the set intersections of WatchPermissionSets in the client side is not viable 42 | or there is a strict application requirement to use consume the computed permissions. 43 | """ 44 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 45 | context.set_details('Method not implemented!') 46 | raise NotImplementedError('Method not implemented!') 47 | 48 | 49 | def add_WatchPermissionsServiceServicer_to_server(servicer, server): 50 | rpc_method_handlers = { 51 | 'WatchPermissions': grpc.unary_stream_rpc_method_handler( 52 | servicer.WatchPermissions, 53 | request_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsRequest.FromString, 54 | response_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsResponse.SerializeToString, 55 | ), 56 | } 57 | generic_handler = grpc.method_handlers_generic_handler( 58 | 'authzed.api.materialize.v0.WatchPermissionsService', rpc_method_handlers) 59 | server.add_generic_rpc_handlers((generic_handler,)) 60 | server.add_registered_method_handlers('authzed.api.materialize.v0.WatchPermissionsService', rpc_method_handlers) 61 | 62 | 63 | # This class is part of an EXPERIMENTAL API. 64 | class WatchPermissionsService(object): 65 | """Missing associated documentation comment in .proto file.""" 66 | 67 | @staticmethod 68 | def WatchPermissions(request, 69 | target, 70 | options=(), 71 | channel_credentials=None, 72 | call_credentials=None, 73 | insecure=False, 74 | compression=None, 75 | wait_for_ready=None, 76 | timeout=None, 77 | metadata=None): 78 | return grpc.experimental.unary_stream( 79 | request, 80 | target, 81 | '/authzed.api.materialize.v0.WatchPermissionsService/WatchPermissions', 82 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsRequest.SerializeToString, 83 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissions__pb2.WatchPermissionsResponse.FromString, 84 | options, 85 | channel_credentials, 86 | insecure, 87 | call_credentials, 88 | compression, 89 | wait_for_ready, 90 | timeout, 91 | metadata, 92 | _registered_method=True) 93 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissions_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.materialize.v0.watchpermissions_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class WatchPermissionsServiceStub: 21 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 22 | WatchPermissions: grpc.UnaryStreamMultiCallable[ 23 | authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsRequest, 24 | authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsResponse, 25 | ] 26 | """WatchPermissions returns a stream of PermissionChange events for the given permissions. 27 | 28 | WatchPermissions is a long-running RPC, and will stream events until the client 29 | closes the connection or the server terminates the stream. The consumer is responsible of 30 | keeping track of the last seen revision and resuming the stream from that point in the event 31 | of disconnection or client-side restarts. 32 | 33 | The API does not offer a sharding mechanism and thus there should only be one consumer per target system. 34 | Implementing an active-active HA consumer setup over the same target system will require coordinating which 35 | revisions have been consumed in order to prevent transitioning to an inconsistent state. 36 | 37 | Usage of WatchPermissions requires to be explicitly enabled on the service, including the permissions to be 38 | watched. It requires more resources and is less performant than WatchPermissionsSets. It's usage 39 | is only recommended when performing the set intersections of WatchPermissionSets in the client side is not viable 40 | or there is a strict application requirement to use consume the computed permissions. 41 | """ 42 | 43 | class WatchPermissionsServiceAsyncStub: 44 | WatchPermissions: grpc.aio.UnaryStreamMultiCallable[ 45 | authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsRequest, 46 | authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsResponse, 47 | ] 48 | """WatchPermissions returns a stream of PermissionChange events for the given permissions. 49 | 50 | WatchPermissions is a long-running RPC, and will stream events until the client 51 | closes the connection or the server terminates the stream. The consumer is responsible of 52 | keeping track of the last seen revision and resuming the stream from that point in the event 53 | of disconnection or client-side restarts. 54 | 55 | The API does not offer a sharding mechanism and thus there should only be one consumer per target system. 56 | Implementing an active-active HA consumer setup over the same target system will require coordinating which 57 | revisions have been consumed in order to prevent transitioning to an inconsistent state. 58 | 59 | Usage of WatchPermissions requires to be explicitly enabled on the service, including the permissions to be 60 | watched. It requires more resources and is less performant than WatchPermissionsSets. It's usage 61 | is only recommended when performing the set intersections of WatchPermissionSets in the client side is not viable 62 | or there is a strict application requirement to use consume the computed permissions. 63 | """ 64 | 65 | class WatchPermissionsServiceServicer(metaclass=abc.ABCMeta): 66 | @abc.abstractmethod 67 | def WatchPermissions( 68 | self, 69 | request: authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsRequest, 70 | context: _ServicerContext, 71 | ) -> typing.Union[collections.abc.Iterator[authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsResponse], collections.abc.AsyncIterator[authzed.api.materialize.v0.watchpermissions_pb2.WatchPermissionsResponse]]: 72 | """WatchPermissions returns a stream of PermissionChange events for the given permissions. 73 | 74 | WatchPermissions is a long-running RPC, and will stream events until the client 75 | closes the connection or the server terminates the stream. The consumer is responsible of 76 | keeping track of the last seen revision and resuming the stream from that point in the event 77 | of disconnection or client-side restarts. 78 | 79 | The API does not offer a sharding mechanism and thus there should only be one consumer per target system. 80 | Implementing an active-active HA consumer setup over the same target system will require coordinating which 81 | revisions have been consumed in order to prevent transitioning to an inconsistent state. 82 | 83 | Usage of WatchPermissions requires to be explicitly enabled on the service, including the permissions to be 84 | watched. It requires more resources and is less performant than WatchPermissionsSets. It's usage 85 | is only recommended when performing the set intersections of WatchPermissionSets in the client side is not viable 86 | or there is a strict application requirement to use consume the computed permissions. 87 | """ 88 | 89 | def add_WatchPermissionsServiceServicer_to_server(servicer: WatchPermissionsServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 90 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissionsets_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/materialize/v0/watchpermissionsets.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/materialize/v0/watchpermissionsets.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v1 import core_pb2 as authzed_dot_api_dot_v1_dot_core__pb2 26 | 27 | 28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n4authzed/api/materialize/v0/watchpermissionsets.proto\x12\x1a\x61uthzed.api.materialize.v0\x1a\x19\x61uthzed/api/v1/core.proto\"n\n\x1aWatchPermissionSetsRequest\x12P\n\x17optional_starting_after\x18\x01 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x15optionalStartingAfter\"\xad\x03\n\x1bWatchPermissionSetsResponse\x12I\n\x06\x63hange\x18\x01 \x01(\x0b\x32/.authzed.api.materialize.v0.PermissionSetChangeH\x00R\x06\x63hange\x12I\n\x12\x63ompleted_revision\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenH\x00R\x11\x63ompletedRevision\x12\x81\x01\n\x1flookup_permission_sets_required\x18\x03 \x01(\x0b\x32\x38.authzed.api.materialize.v0.LookupPermissionSetsRequiredH\x00R\x1clookupPermissionSetsRequired\x12h\n\x16\x62reaking_schema_change\x18\x04 \x01(\x0b\x32\x30.authzed.api.materialize.v0.BreakingSchemaChangeH\x00R\x14\x62reakingSchemaChangeB\n\n\x08response\"\xdd\x01\n\x06\x43ursor\x12\x14\n\x05limit\x18\x01 \x01(\rR\x05limit\x12.\n\x05token\x18\x04 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x05token\x12%\n\x0estarting_index\x18\x05 \x01(\rR\rstartingIndex\x12+\n\x11\x63ompleted_members\x18\x06 \x01(\x08R\x10\x63ompletedMembers\x12!\n\x0cstarting_key\x18\x07 \x01(\tR\x0bstartingKey\x12\x16\n\x06\x63ursor\x18\x08 \x01(\tR\x06\x63ursor\"\xe8\x01\n\x1bLookupPermissionSetsRequest\x12\x14\n\x05limit\x18\x01 \x01(\rR\x05limit\x12J\n\x14optional_at_revision\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x12optionalAtRevision\x12g\n\x1eoptional_starting_after_cursor\x18\x04 \x01(\x0b\x32\".authzed.api.materialize.v0.CursorR\x1boptionalStartingAfterCursor\"\xa3\x01\n\x1cLookupPermissionSetsResponse\x12G\n\x06\x63hange\x18\x01 \x01(\x0b\x32/.authzed.api.materialize.v0.PermissionSetChangeR\x06\x63hange\x12:\n\x06\x63ursor\x18\x02 \x01(\x0b\x32\".authzed.api.materialize.v0.CursorR\x06\x63ursor\"\xfc\x03\n\x13PermissionSetChange\x12\x39\n\x0b\x61t_revision\x18\x01 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\natRevision\x12Z\n\toperation\x18\x02 \x01(\x0e\x32<.authzed.api.materialize.v0.PermissionSetChange.SetOperationR\toperation\x12G\n\nparent_set\x18\x03 \x01(\x0b\x32(.authzed.api.materialize.v0.SetReferenceR\tparentSet\x12G\n\tchild_set\x18\x04 \x01(\x0b\x32(.authzed.api.materialize.v0.SetReferenceH\x00R\x08\x63hildSet\x12P\n\x0c\x63hild_member\x18\x05 \x01(\x0b\x32+.authzed.api.materialize.v0.MemberReferenceH\x00R\x0b\x63hildMember\"a\n\x0cSetOperation\x12\x1d\n\x19SET_OPERATION_UNSPECIFIED\x10\x00\x12\x17\n\x13SET_OPERATION_ADDED\x10\x01\x12\x19\n\x15SET_OPERATION_REMOVED\x10\x02\x42\x07\n\x05\x63hild\"\x82\x01\n\x0cSetReference\x12\x1f\n\x0bobject_type\x18\x01 \x01(\tR\nobjectType\x12\x1b\n\tobject_id\x18\x02 \x01(\tR\x08objectId\x12\x34\n\x16permission_or_relation\x18\x03 \x01(\tR\x14permissionOrRelation\"\x96\x01\n\x0fMemberReference\x12\x1f\n\x0bobject_type\x18\x01 \x01(\tR\nobjectType\x12\x1b\n\tobject_id\x18\x02 \x01(\tR\x08objectId\x12\x45\n\x1foptional_permission_or_relation\x18\x03 \x01(\tR\x1coptionalPermissionOrRelation\"f\n\x1cLookupPermissionSetsRequired\x12\x46\n\x12required_lookup_at\x18\x01 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x10requiredLookupAt\"M\n\x14\x42reakingSchemaChange\x12\x35\n\tchange_at\x18\x01 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x08\x63hangeAt2\xb9\x02\n\x1aWatchPermissionSetsService\x12\x8a\x01\n\x13WatchPermissionSets\x12\x36.authzed.api.materialize.v0.WatchPermissionSetsRequest\x1a\x37.authzed.api.materialize.v0.WatchPermissionSetsResponse\"\x00\x30\x01\x12\x8d\x01\n\x14LookupPermissionSets\x12\x37.authzed.api.materialize.v0.LookupPermissionSetsRequest\x1a\x38.authzed.api.materialize.v0.LookupPermissionSetsResponse\"\x00\x30\x01\x42\x62\n\x1e\x63om.authzed.api.materialize.v0P\x01Z>github.com/authzed/authzed-go/proto/authzed/api/materialize/v0b\x06proto3') 29 | 30 | _globals = globals() 31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.materialize.v0.watchpermissionsets_pb2', _globals) 33 | if not _descriptor._USE_C_DESCRIPTORS: 34 | _globals['DESCRIPTOR']._loaded_options = None 35 | _globals['DESCRIPTOR']._serialized_options = b'\n\036com.authzed.api.materialize.v0P\001Z>github.com/authzed/authzed-go/proto/authzed/api/materialize/v0' 36 | _globals['_WATCHPERMISSIONSETSREQUEST']._serialized_start=111 37 | _globals['_WATCHPERMISSIONSETSREQUEST']._serialized_end=221 38 | _globals['_WATCHPERMISSIONSETSRESPONSE']._serialized_start=224 39 | _globals['_WATCHPERMISSIONSETSRESPONSE']._serialized_end=653 40 | _globals['_CURSOR']._serialized_start=656 41 | _globals['_CURSOR']._serialized_end=877 42 | _globals['_LOOKUPPERMISSIONSETSREQUEST']._serialized_start=880 43 | _globals['_LOOKUPPERMISSIONSETSREQUEST']._serialized_end=1112 44 | _globals['_LOOKUPPERMISSIONSETSRESPONSE']._serialized_start=1115 45 | _globals['_LOOKUPPERMISSIONSETSRESPONSE']._serialized_end=1278 46 | _globals['_PERMISSIONSETCHANGE']._serialized_start=1281 47 | _globals['_PERMISSIONSETCHANGE']._serialized_end=1789 48 | _globals['_PERMISSIONSETCHANGE_SETOPERATION']._serialized_start=1683 49 | _globals['_PERMISSIONSETCHANGE_SETOPERATION']._serialized_end=1780 50 | _globals['_SETREFERENCE']._serialized_start=1792 51 | _globals['_SETREFERENCE']._serialized_end=1922 52 | _globals['_MEMBERREFERENCE']._serialized_start=1925 53 | _globals['_MEMBERREFERENCE']._serialized_end=2075 54 | _globals['_LOOKUPPERMISSIONSETSREQUIRED']._serialized_start=2077 55 | _globals['_LOOKUPPERMISSIONSETSREQUIRED']._serialized_end=2179 56 | _globals['_BREAKINGSCHEMACHANGE']._serialized_start=2181 57 | _globals['_BREAKINGSCHEMACHANGE']._serialized_end=2258 58 | _globals['_WATCHPERMISSIONSETSSERVICE']._serialized_start=2261 59 | _globals['_WATCHPERMISSIONSETSSERVICE']._serialized_end=2574 60 | # @@protoc_insertion_point(module_scope) 61 | -------------------------------------------------------------------------------- /authzed/api/materialize/v0/watchpermissionsets_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | from authzed.api.materialize.v0 import watchpermissionsets_pb2 as authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2 6 | 7 | 8 | class WatchPermissionSetsServiceStub(object): 9 | """Missing associated documentation comment in .proto file.""" 10 | 11 | def __init__(self, channel): 12 | """Constructor. 13 | 14 | Args: 15 | channel: A grpc.Channel. 16 | """ 17 | self.WatchPermissionSets = channel.unary_stream( 18 | '/authzed.api.materialize.v0.WatchPermissionSetsService/WatchPermissionSets', 19 | request_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsRequest.SerializeToString, 20 | response_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsResponse.FromString, 21 | _registered_method=True) 22 | self.LookupPermissionSets = channel.unary_stream( 23 | '/authzed.api.materialize.v0.WatchPermissionSetsService/LookupPermissionSets', 24 | request_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsRequest.SerializeToString, 25 | response_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsResponse.FromString, 26 | _registered_method=True) 27 | 28 | 29 | class WatchPermissionSetsServiceServicer(object): 30 | """Missing associated documentation comment in .proto file.""" 31 | 32 | def WatchPermissionSets(self, request, context): 33 | """WatchPermissionSets returns a stream of changes to the sets which can be used to compute the watched permissions. 34 | 35 | WatchPermissionSets lets consumers achieve the same thing as WatchPermissions, but trades off a simpler usage model with 36 | significantly lower computational requirements. Unlike WatchPermissions, this method returns changes to the sets of permissions, 37 | rather than the individual permissions. Permission sets are a normalized form of the computed permissions, which 38 | means that the consumer must perform an extra computation over this representation to obtain the final computed 39 | permissions, typically by intersecting the provided sets. 40 | 41 | For example, this would look like a JOIN between the 42 | materialize permission sets table in a target relation database, the table with the resources to authorize access 43 | to, and the table with the subject (e.g. a user). 44 | 45 | In exchange, the number of changes issued by WatchPermissionSets will be several orders of magnitude less than those 46 | emitted by WatchPermissions, which has several implications: 47 | - significantly less resources to compute the sets 48 | - significantly less messages to stream over the network 49 | - significantly less events to ingest on the consumer side 50 | - less ingestion lag from the origin SpiceDB mutation 51 | 52 | The type of scenarios WatchPermissionSets is particularly well suited is when a single change 53 | in the origin SpiceDB can yield millions of changes. For example, in the GitHub authorization model, assigning a role 54 | to a top-level team of an organization with hundreds of thousands of employees can lead to an explosion of 55 | permission change events that would require a lot of computational resources to process, both on Materialize and 56 | the consumer side. 57 | 58 | WatchPermissionSets is thus recommended for any larger scale use case where the fan-out in permission changes that 59 | emerges from a specific schema and data shape is too large to handle effectively. 60 | 61 | The API does not offer a sharding mechanism and thus there should only be one consumer per target system. 62 | Implementing an active-active HA consumer setup over the same target system will require coordinating which 63 | revisions have been consumed in order to prevent transitioning to an inconsistent state. 64 | """ 65 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 66 | context.set_details('Method not implemented!') 67 | raise NotImplementedError('Method not implemented!') 68 | 69 | def LookupPermissionSets(self, request, context): 70 | """LookupPermissionSets returns the current state of the permission sets which can be used to derive the computed permissions. 71 | It's typically used to backfill the state of the permission sets in the consumer side. 72 | 73 | It's a cursored API and the consumer is responsible to keep track of the cursor and use it on each subsequent call. 74 | Each stream will return permission sets defined by the specified request limit. The server will keep streaming until 75 | the sets per stream is hit, or the current state of the sets is reached, 76 | whatever happens first, and then close the stream. The server will indicate there are no more changes to stream 77 | through the `completed_members` in the cursor. 78 | 79 | There may be many elements to stream, and so the consumer should be prepared to resume the stream from the last 80 | cursor received. Once completed, the consumer may start streaming permission set changes using WatchPermissionSets 81 | and the revision token from the last LookupPermissionSets response. 82 | """ 83 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 84 | context.set_details('Method not implemented!') 85 | raise NotImplementedError('Method not implemented!') 86 | 87 | 88 | def add_WatchPermissionSetsServiceServicer_to_server(servicer, server): 89 | rpc_method_handlers = { 90 | 'WatchPermissionSets': grpc.unary_stream_rpc_method_handler( 91 | servicer.WatchPermissionSets, 92 | request_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsRequest.FromString, 93 | response_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsResponse.SerializeToString, 94 | ), 95 | 'LookupPermissionSets': grpc.unary_stream_rpc_method_handler( 96 | servicer.LookupPermissionSets, 97 | request_deserializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsRequest.FromString, 98 | response_serializer=authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsResponse.SerializeToString, 99 | ), 100 | } 101 | generic_handler = grpc.method_handlers_generic_handler( 102 | 'authzed.api.materialize.v0.WatchPermissionSetsService', rpc_method_handlers) 103 | server.add_generic_rpc_handlers((generic_handler,)) 104 | server.add_registered_method_handlers('authzed.api.materialize.v0.WatchPermissionSetsService', rpc_method_handlers) 105 | 106 | 107 | # This class is part of an EXPERIMENTAL API. 108 | class WatchPermissionSetsService(object): 109 | """Missing associated documentation comment in .proto file.""" 110 | 111 | @staticmethod 112 | def WatchPermissionSets(request, 113 | target, 114 | options=(), 115 | channel_credentials=None, 116 | call_credentials=None, 117 | insecure=False, 118 | compression=None, 119 | wait_for_ready=None, 120 | timeout=None, 121 | metadata=None): 122 | return grpc.experimental.unary_stream( 123 | request, 124 | target, 125 | '/authzed.api.materialize.v0.WatchPermissionSetsService/WatchPermissionSets', 126 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsRequest.SerializeToString, 127 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.WatchPermissionSetsResponse.FromString, 128 | options, 129 | channel_credentials, 130 | insecure, 131 | call_credentials, 132 | compression, 133 | wait_for_ready, 134 | timeout, 135 | metadata, 136 | _registered_method=True) 137 | 138 | @staticmethod 139 | def LookupPermissionSets(request, 140 | target, 141 | options=(), 142 | channel_credentials=None, 143 | call_credentials=None, 144 | insecure=False, 145 | compression=None, 146 | wait_for_ready=None, 147 | timeout=None, 148 | metadata=None): 149 | return grpc.experimental.unary_stream( 150 | request, 151 | target, 152 | '/authzed.api.materialize.v0.WatchPermissionSetsService/LookupPermissionSets', 153 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsRequest.SerializeToString, 154 | authzed_dot_api_dot_materialize_dot_v0_dot_watchpermissionsets__pb2.LookupPermissionSetsResponse.FromString, 155 | options, 156 | channel_credentials, 157 | insecure, 158 | call_credentials, 159 | compression, 160 | wait_for_ready, 161 | timeout, 162 | metadata, 163 | _registered_method=True) 164 | -------------------------------------------------------------------------------- /authzed/api/v0/core_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v0/core.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v0/core.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 26 | from validate import validate_pb2 as validate_dot_validate__pb2 27 | 28 | 29 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x61uthzed/api/v0/core.proto\x12\x0e\x61uthzed.api.v0\x1a\x1b\x62uf/validate/validate.proto\x1a\x17validate/validate.proto\"\xac\x01\n\rRelationTuple\x12\x61\n\x13object_and_relation\x18\x01 \x01(\x0b\x32!.authzed.api.v0.ObjectAndRelationB\x0e\xfa\x42\x05\x8a\x01\x02\x10\x01\xbaH\x03\xc8\x01\x01R\x11objectAndRelation\x12\x38\n\x04user\x18\x02 \x01(\x0b\x32\x14.authzed.api.v0.UserB\x0e\xfa\x42\x05\x8a\x01\x02\x10\x01\xbaH\x03\xc8\x01\x01R\x04user\"\xcd\x03\n\x11ObjectAndRelation\x12\xaf\x01\n\tnamespace\x18\x01 \x01(\tB\x90\x01\xfa\x42\x45rC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaHErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12\x87\x01\n\tobject_id\x18\x02 \x01(\tBj\xfa\x42\x32r0(\x80\x01\x32+^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$\xbaH2r0(\x80\x01\x32+^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$R\x08objectId\x12|\n\x08relation\x18\x03 \x01(\tB`\xfa\x42-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\xbaH-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$R\x08relation\"\xc3\x02\n\x11RelationReference\x12\xaf\x01\n\tnamespace\x18\x01 \x01(\tB\x90\x01\xfa\x42\x45rC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaHErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$R\tnamespace\x12|\n\x08relation\x18\x03 \x01(\tB`\xfa\x42-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\xbaH-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$R\x08relation\"m\n\x04User\x12M\n\x07userset\x18\x02 \x01(\x0b\x32!.authzed.api.v0.ObjectAndRelationB\x0e\xfa\x42\x05\x8a\x01\x02\x10\x01\xbaH\x03\xc8\x01\x01H\x00R\x07usersetB\x16\n\nuser_oneof\x12\x08\xf8\x42\x01\xbaH\x02\x08\x01\x42H\n\x12\x63om.authzed.api.v0Z2github.com/authzed/authzed-go/proto/authzed/api/v0b\x06proto3') 30 | 31 | _globals = globals() 32 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 33 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v0.core_pb2', _globals) 34 | if not _descriptor._USE_C_DESCRIPTORS: 35 | _globals['DESCRIPTOR']._loaded_options = None 36 | _globals['DESCRIPTOR']._serialized_options = b'\n\022com.authzed.api.v0Z2github.com/authzed/authzed-go/proto/authzed/api/v0' 37 | _globals['_RELATIONTUPLE'].fields_by_name['object_and_relation']._loaded_options = None 38 | _globals['_RELATIONTUPLE'].fields_by_name['object_and_relation']._serialized_options = b'\372B\005\212\001\002\020\001\272H\003\310\001\001' 39 | _globals['_RELATIONTUPLE'].fields_by_name['user']._loaded_options = None 40 | _globals['_RELATIONTUPLE'].fields_by_name['user']._serialized_options = b'\372B\005\212\001\002\020\001\272H\003\310\001\001' 41 | _globals['_OBJECTANDRELATION'].fields_by_name['namespace']._loaded_options = None 42 | _globals['_OBJECTANDRELATION'].fields_by_name['namespace']._serialized_options = b'\372BErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$\272HErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$' 43 | _globals['_OBJECTANDRELATION'].fields_by_name['object_id']._loaded_options = None 44 | _globals['_OBJECTANDRELATION'].fields_by_name['object_id']._serialized_options = b'\372B2r0(\200\0012+^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$\272H2r0(\200\0012+^(([a-zA-Z0-9_][a-zA-Z0-9/_|-]{0,127})|\\*)$' 45 | _globals['_OBJECTANDRELATION'].fields_by_name['relation']._loaded_options = None 46 | _globals['_OBJECTANDRELATION'].fields_by_name['relation']._serialized_options = b'\372B-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\272H-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$' 47 | _globals['_RELATIONREFERENCE'].fields_by_name['namespace']._loaded_options = None 48 | _globals['_RELATIONREFERENCE'].fields_by_name['namespace']._serialized_options = b'\372BErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$\272HErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-z][a-z0-9_]{1,62}[a-z0-9]$' 49 | _globals['_RELATIONREFERENCE'].fields_by_name['relation']._loaded_options = None 50 | _globals['_RELATIONREFERENCE'].fields_by_name['relation']._serialized_options = b'\372B-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$\272H-r+(@2\'^(\\.\\.\\.|[a-z][a-z0-9_]{1,62}[a-z0-9])$' 51 | _globals['_USER'].oneofs_by_name['user_oneof']._loaded_options = None 52 | _globals['_USER'].oneofs_by_name['user_oneof']._serialized_options = b'\370B\001\272H\002\010\001' 53 | _globals['_USER'].fields_by_name['userset']._loaded_options = None 54 | _globals['_USER'].fields_by_name['userset']._serialized_options = b'\372B\005\212\001\002\020\001\272H\003\310\001\001' 55 | _globals['_RELATIONTUPLE']._serialized_start=100 56 | _globals['_RELATIONTUPLE']._serialized_end=272 57 | _globals['_OBJECTANDRELATION']._serialized_start=275 58 | _globals['_OBJECTANDRELATION']._serialized_end=736 59 | _globals['_RELATIONREFERENCE']._serialized_start=739 60 | _globals['_RELATIONREFERENCE']._serialized_end=1062 61 | _globals['_USER']._serialized_start=1064 62 | _globals['_USER']._serialized_end=1173 63 | # @@protoc_insertion_point(module_scope) 64 | -------------------------------------------------------------------------------- /authzed/api/v0/core_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import builtins 7 | import google.protobuf.descriptor 8 | import google.protobuf.message 9 | import typing 10 | 11 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 12 | 13 | @typing.final 14 | class RelationTuple(google.protobuf.message.Message): 15 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 16 | 17 | OBJECT_AND_RELATION_FIELD_NUMBER: builtins.int 18 | USER_FIELD_NUMBER: builtins.int 19 | @property 20 | def object_and_relation(self) -> global___ObjectAndRelation: 21 | """Each tupleset specifies keys of a set of relation tuples. The set can 22 | include a single tuple key, or all tuples with a given object ID or 23 | userset in a namespace, optionally constrained by a relation name. 24 | 25 | examples: 26 | doc:readme#viewer@group:eng#member (fully specified) 27 | doc:*#*#group:eng#member (all tuples that this userset relates to) 28 | doc:12345#*#* (all tuples with a direct relationship to a document) 29 | doc:12345#writer#* (all tuples with direct write relationship with the 30 | document) doc:#writer#group:eng#member (all tuples that eng group has write 31 | relationship) 32 | """ 33 | 34 | @property 35 | def user(self) -> global___User: ... 36 | def __init__( 37 | self, 38 | *, 39 | object_and_relation: global___ObjectAndRelation | None = ..., 40 | user: global___User | None = ..., 41 | ) -> None: ... 42 | def HasField(self, field_name: typing.Literal["object_and_relation", b"object_and_relation", "user", b"user"]) -> builtins.bool: ... 43 | def ClearField(self, field_name: typing.Literal["object_and_relation", b"object_and_relation", "user", b"user"]) -> None: ... 44 | 45 | global___RelationTuple = RelationTuple 46 | 47 | @typing.final 48 | class ObjectAndRelation(google.protobuf.message.Message): 49 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 50 | 51 | NAMESPACE_FIELD_NUMBER: builtins.int 52 | OBJECT_ID_FIELD_NUMBER: builtins.int 53 | RELATION_FIELD_NUMBER: builtins.int 54 | namespace: builtins.str 55 | object_id: builtins.str 56 | relation: builtins.str 57 | def __init__( 58 | self, 59 | *, 60 | namespace: builtins.str = ..., 61 | object_id: builtins.str = ..., 62 | relation: builtins.str = ..., 63 | ) -> None: ... 64 | def ClearField(self, field_name: typing.Literal["namespace", b"namespace", "object_id", b"object_id", "relation", b"relation"]) -> None: ... 65 | 66 | global___ObjectAndRelation = ObjectAndRelation 67 | 68 | @typing.final 69 | class RelationReference(google.protobuf.message.Message): 70 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 71 | 72 | NAMESPACE_FIELD_NUMBER: builtins.int 73 | RELATION_FIELD_NUMBER: builtins.int 74 | namespace: builtins.str 75 | relation: builtins.str 76 | def __init__( 77 | self, 78 | *, 79 | namespace: builtins.str = ..., 80 | relation: builtins.str = ..., 81 | ) -> None: ... 82 | def ClearField(self, field_name: typing.Literal["namespace", b"namespace", "relation", b"relation"]) -> None: ... 83 | 84 | global___RelationReference = RelationReference 85 | 86 | @typing.final 87 | class User(google.protobuf.message.Message): 88 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 89 | 90 | USERSET_FIELD_NUMBER: builtins.int 91 | @property 92 | def userset(self) -> global___ObjectAndRelation: ... 93 | def __init__( 94 | self, 95 | *, 96 | userset: global___ObjectAndRelation | None = ..., 97 | ) -> None: ... 98 | def HasField(self, field_name: typing.Literal["user_oneof", b"user_oneof", "userset", b"userset"]) -> builtins.bool: ... 99 | def ClearField(self, field_name: typing.Literal["user_oneof", b"user_oneof", "userset", b"userset"]) -> None: ... 100 | def WhichOneof(self, oneof_group: typing.Literal["user_oneof", b"user_oneof"]) -> typing.Literal["userset"] | None: ... 101 | 102 | global___User = User 103 | -------------------------------------------------------------------------------- /authzed/api/v0/core_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /authzed/api/v0/core_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import collections.abc 8 | import grpc 9 | import grpc.aio 10 | import typing 11 | 12 | _T = typing.TypeVar("_T") 13 | 14 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 15 | 16 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 17 | ... 18 | -------------------------------------------------------------------------------- /authzed/api/v0/developer_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v0/developer.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v0/developer.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v0 import core_pb2 as authzed_dot_api_dot_v0_dot_core__pb2 26 | 27 | 28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1e\x61uthzed/api/v0/developer.proto\x12\x0e\x61uthzed.api.v0\x1a\x19\x61uthzed/api/v0/core.proto\"-\n\x13\x46ormatSchemaRequest\x12\x16\n\x06schema\x18\x01 \x01(\tR\x06schema\"w\n\x14\x46ormatSchemaResponse\x12\x34\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\x05\x65rror\x12)\n\x10\x66ormatted_schema\x18\x02 \x01(\tR\x0f\x66ormattedSchema\"C\n\x14UpgradeSchemaRequest\x12+\n\x11namespace_configs\x18\x01 \x03(\tR\x10namespaceConfigs\"v\n\x15UpgradeSchemaResponse\x12\x34\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\x05\x65rror\x12\'\n\x0fupgraded_schema\x18\x02 \x01(\tR\x0eupgradedSchema\"\xa7\x01\n\x0cShareRequest\x12\x16\n\x06schema\x18\x01 \x01(\tR\x06schema\x12-\n\x12relationships_yaml\x18\x02 \x01(\tR\x11relationshipsYaml\x12\'\n\x0fvalidation_yaml\x18\x03 \x01(\tR\x0evalidationYaml\x12\'\n\x0f\x61ssertions_yaml\x18\x04 \x01(\tR\x0e\x61ssertionsYaml\"8\n\rShareResponse\x12\'\n\x0fshare_reference\x18\x01 \x01(\tR\x0eshareReference\"=\n\x12LookupShareRequest\x12\'\n\x0fshare_reference\x18\x01 \x01(\tR\x0eshareReference\"\xe2\x02\n\x13LookupShareResponse\x12H\n\x06status\x18\x01 \x01(\x0e\x32\x30.authzed.api.v0.LookupShareResponse.LookupStatusR\x06status\x12\x16\n\x06schema\x18\x02 \x01(\tR\x06schema\x12-\n\x12relationships_yaml\x18\x03 \x01(\tR\x11relationshipsYaml\x12\'\n\x0fvalidation_yaml\x18\x04 \x01(\tR\x0evalidationYaml\x12\'\n\x0f\x61ssertions_yaml\x18\x05 \x01(\tR\x0e\x61ssertionsYaml\"h\n\x0cLookupStatus\x12\x15\n\x11UNKNOWN_REFERENCE\x10\x00\x12\x14\n\x10\x46\x41ILED_TO_LOOKUP\x10\x01\x12\x13\n\x0fVALID_REFERENCE\x10\x02\x12\x16\n\x12UPGRADED_REFERENCE\x10\x03\"s\n\x0eRequestContext\x12\x16\n\x06schema\x18\x01 \x01(\tR\x06schema\x12\x43\n\rrelationships\x18\x02 \x03(\x0b\x32\x1d.authzed.api.v0.RelationTupleR\rrelationshipsJ\x04\x08\x03\x10\x04\"\x9c\x01\n\x10\x45\x64itCheckRequest\x12\x38\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x1e.authzed.api.v0.RequestContextR\x07\x63ontext\x12N\n\x13\x63heck_relationships\x18\x02 \x03(\x0b\x32\x1d.authzed.api.v0.RelationTupleR\x12\x63heckRelationships\"\xa7\x01\n\x0f\x45\x64itCheckResult\x12\x41\n\x0crelationship\x18\x01 \x01(\x0b\x32\x1d.authzed.api.v0.RelationTupleR\x0crelationship\x12\x1b\n\tis_member\x18\x02 \x01(\x08R\x08isMember\x12\x34\n\x05\x65rror\x18\x03 \x01(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\x05\x65rror\"\xa0\x01\n\x11\x45\x64itCheckResponse\x12\x45\n\x0erequest_errors\x18\x01 \x03(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\rrequestErrors\x12\x44\n\rcheck_results\x18\x02 \x03(\x0b\x32\x1f.authzed.api.v0.EditCheckResultR\x0c\x63heckResults\"\xd3\x01\n\x0fValidateRequest\x12\x38\n\x07\x63ontext\x18\x01 \x01(\x0b\x32\x1e.authzed.api.v0.RequestContextR\x07\x63ontext\x12\'\n\x0fvalidation_yaml\x18\x03 \x01(\tR\x0evalidationYaml\x12\x34\n\x16update_validation_yaml\x18\x04 \x01(\x08R\x14updateValidationYaml\x12\'\n\x0f\x61ssertions_yaml\x18\x05 \x01(\tR\x0e\x61ssertionsYaml\"\xde\x01\n\x10ValidateResponse\x12\x45\n\x0erequest_errors\x18\x01 \x03(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\rrequestErrors\x12K\n\x11validation_errors\x18\x02 \x03(\x0b\x32\x1e.authzed.api.v0.DeveloperErrorR\x10validationErrors\x12\x36\n\x17updated_validation_yaml\x18\x03 \x01(\tR\x15updatedValidationYaml\"\xee\x04\n\x0e\x44\x65veloperError\x12\x18\n\x07message\x18\x01 \x01(\tR\x07message\x12\x12\n\x04line\x18\x02 \x01(\rR\x04line\x12\x16\n\x06\x63olumn\x18\x03 \x01(\rR\x06\x63olumn\x12=\n\x06source\x18\x04 \x01(\x0e\x32%.authzed.api.v0.DeveloperError.SourceR\x06source\x12<\n\x04kind\x18\x05 \x01(\x0e\x32(.authzed.api.v0.DeveloperError.ErrorKindR\x04kind\x12\x12\n\x04path\x18\x06 \x03(\tR\x04path\x12\x18\n\x07\x63ontext\x18\x07 \x01(\tR\x07\x63ontext\"o\n\x06Source\x12\x12\n\x0eUNKNOWN_SOURCE\x10\x00\x12\n\n\x06SCHEMA\x10\x01\x12\x10\n\x0cRELATIONSHIP\x10\x02\x12\x13\n\x0fVALIDATION_YAML\x10\x03\x12\x0f\n\x0b\x43HECK_WATCH\x10\x04\x12\r\n\tASSERTION\x10\x05\"\xf9\x01\n\tErrorKind\x12\x10\n\x0cUNKNOWN_KIND\x10\x00\x12\x0f\n\x0bPARSE_ERROR\x10\x01\x12\x10\n\x0cSCHEMA_ISSUE\x10\x02\x12\x1a\n\x16\x44UPLICATE_RELATIONSHIP\x10\x03\x12!\n\x1dMISSING_EXPECTED_RELATIONSHIP\x10\x04\x12\x1c\n\x18\x45XTRA_RELATIONSHIP_FOUND\x10\x05\x12\x17\n\x13UNKNOWN_OBJECT_TYPE\x10\x06\x12\x14\n\x10UNKNOWN_RELATION\x10\x07\x12\x15\n\x11MAXIMUM_RECURSION\x10\x08\x12\x14\n\x10\x41SSERTION_FAILED\x10\t2\x97\x04\n\x10\x44\x65veloperService\x12R\n\tEditCheck\x12 .authzed.api.v0.EditCheckRequest\x1a!.authzed.api.v0.EditCheckResponse\"\x00\x12O\n\x08Validate\x12\x1f.authzed.api.v0.ValidateRequest\x1a .authzed.api.v0.ValidateResponse\"\x00\x12\x46\n\x05Share\x12\x1c.authzed.api.v0.ShareRequest\x1a\x1d.authzed.api.v0.ShareResponse\"\x00\x12Y\n\x0cLookupShared\x12\".authzed.api.v0.LookupShareRequest\x1a#.authzed.api.v0.LookupShareResponse\"\x00\x12^\n\rUpgradeSchema\x12$.authzed.api.v0.UpgradeSchemaRequest\x1a%.authzed.api.v0.UpgradeSchemaResponse\"\x00\x12[\n\x0c\x46ormatSchema\x12#.authzed.api.v0.FormatSchemaRequest\x1a$.authzed.api.v0.FormatSchemaResponse\"\x00\x42H\n\x12\x63om.authzed.api.v0Z2github.com/authzed/authzed-go/proto/authzed/api/v0b\x06proto3') 29 | 30 | _globals = globals() 31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v0.developer_pb2', _globals) 33 | if not _descriptor._USE_C_DESCRIPTORS: 34 | _globals['DESCRIPTOR']._loaded_options = None 35 | _globals['DESCRIPTOR']._serialized_options = b'\n\022com.authzed.api.v0Z2github.com/authzed/authzed-go/proto/authzed/api/v0' 36 | _globals['_FORMATSCHEMAREQUEST']._serialized_start=77 37 | _globals['_FORMATSCHEMAREQUEST']._serialized_end=122 38 | _globals['_FORMATSCHEMARESPONSE']._serialized_start=124 39 | _globals['_FORMATSCHEMARESPONSE']._serialized_end=243 40 | _globals['_UPGRADESCHEMAREQUEST']._serialized_start=245 41 | _globals['_UPGRADESCHEMAREQUEST']._serialized_end=312 42 | _globals['_UPGRADESCHEMARESPONSE']._serialized_start=314 43 | _globals['_UPGRADESCHEMARESPONSE']._serialized_end=432 44 | _globals['_SHAREREQUEST']._serialized_start=435 45 | _globals['_SHAREREQUEST']._serialized_end=602 46 | _globals['_SHARERESPONSE']._serialized_start=604 47 | _globals['_SHARERESPONSE']._serialized_end=660 48 | _globals['_LOOKUPSHAREREQUEST']._serialized_start=662 49 | _globals['_LOOKUPSHAREREQUEST']._serialized_end=723 50 | _globals['_LOOKUPSHARERESPONSE']._serialized_start=726 51 | _globals['_LOOKUPSHARERESPONSE']._serialized_end=1080 52 | _globals['_LOOKUPSHARERESPONSE_LOOKUPSTATUS']._serialized_start=976 53 | _globals['_LOOKUPSHARERESPONSE_LOOKUPSTATUS']._serialized_end=1080 54 | _globals['_REQUESTCONTEXT']._serialized_start=1082 55 | _globals['_REQUESTCONTEXT']._serialized_end=1197 56 | _globals['_EDITCHECKREQUEST']._serialized_start=1200 57 | _globals['_EDITCHECKREQUEST']._serialized_end=1356 58 | _globals['_EDITCHECKRESULT']._serialized_start=1359 59 | _globals['_EDITCHECKRESULT']._serialized_end=1526 60 | _globals['_EDITCHECKRESPONSE']._serialized_start=1529 61 | _globals['_EDITCHECKRESPONSE']._serialized_end=1689 62 | _globals['_VALIDATEREQUEST']._serialized_start=1692 63 | _globals['_VALIDATEREQUEST']._serialized_end=1903 64 | _globals['_VALIDATERESPONSE']._serialized_start=1906 65 | _globals['_VALIDATERESPONSE']._serialized_end=2128 66 | _globals['_DEVELOPERERROR']._serialized_start=2131 67 | _globals['_DEVELOPERERROR']._serialized_end=2753 68 | _globals['_DEVELOPERERROR_SOURCE']._serialized_start=2390 69 | _globals['_DEVELOPERERROR_SOURCE']._serialized_end=2501 70 | _globals['_DEVELOPERERROR_ERRORKIND']._serialized_start=2504 71 | _globals['_DEVELOPERERROR_ERRORKIND']._serialized_end=2753 72 | _globals['_DEVELOPERSERVICE']._serialized_start=2756 73 | _globals['_DEVELOPERSERVICE']._serialized_end=3291 74 | # @@protoc_insertion_point(module_scope) 75 | -------------------------------------------------------------------------------- /authzed/api/v0/developer_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.v0.developer_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class DeveloperServiceStub: 21 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 22 | EditCheck: grpc.UnaryUnaryMultiCallable[ 23 | authzed.api.v0.developer_pb2.EditCheckRequest, 24 | authzed.api.v0.developer_pb2.EditCheckResponse, 25 | ] 26 | 27 | Validate: grpc.UnaryUnaryMultiCallable[ 28 | authzed.api.v0.developer_pb2.ValidateRequest, 29 | authzed.api.v0.developer_pb2.ValidateResponse, 30 | ] 31 | 32 | Share: grpc.UnaryUnaryMultiCallable[ 33 | authzed.api.v0.developer_pb2.ShareRequest, 34 | authzed.api.v0.developer_pb2.ShareResponse, 35 | ] 36 | 37 | LookupShared: grpc.UnaryUnaryMultiCallable[ 38 | authzed.api.v0.developer_pb2.LookupShareRequest, 39 | authzed.api.v0.developer_pb2.LookupShareResponse, 40 | ] 41 | 42 | UpgradeSchema: grpc.UnaryUnaryMultiCallable[ 43 | authzed.api.v0.developer_pb2.UpgradeSchemaRequest, 44 | authzed.api.v0.developer_pb2.UpgradeSchemaResponse, 45 | ] 46 | 47 | FormatSchema: grpc.UnaryUnaryMultiCallable[ 48 | authzed.api.v0.developer_pb2.FormatSchemaRequest, 49 | authzed.api.v0.developer_pb2.FormatSchemaResponse, 50 | ] 51 | 52 | class DeveloperServiceAsyncStub: 53 | EditCheck: grpc.aio.UnaryUnaryMultiCallable[ 54 | authzed.api.v0.developer_pb2.EditCheckRequest, 55 | authzed.api.v0.developer_pb2.EditCheckResponse, 56 | ] 57 | 58 | Validate: grpc.aio.UnaryUnaryMultiCallable[ 59 | authzed.api.v0.developer_pb2.ValidateRequest, 60 | authzed.api.v0.developer_pb2.ValidateResponse, 61 | ] 62 | 63 | Share: grpc.aio.UnaryUnaryMultiCallable[ 64 | authzed.api.v0.developer_pb2.ShareRequest, 65 | authzed.api.v0.developer_pb2.ShareResponse, 66 | ] 67 | 68 | LookupShared: grpc.aio.UnaryUnaryMultiCallable[ 69 | authzed.api.v0.developer_pb2.LookupShareRequest, 70 | authzed.api.v0.developer_pb2.LookupShareResponse, 71 | ] 72 | 73 | UpgradeSchema: grpc.aio.UnaryUnaryMultiCallable[ 74 | authzed.api.v0.developer_pb2.UpgradeSchemaRequest, 75 | authzed.api.v0.developer_pb2.UpgradeSchemaResponse, 76 | ] 77 | 78 | FormatSchema: grpc.aio.UnaryUnaryMultiCallable[ 79 | authzed.api.v0.developer_pb2.FormatSchemaRequest, 80 | authzed.api.v0.developer_pb2.FormatSchemaResponse, 81 | ] 82 | 83 | class DeveloperServiceServicer(metaclass=abc.ABCMeta): 84 | @abc.abstractmethod 85 | def EditCheck( 86 | self, 87 | request: authzed.api.v0.developer_pb2.EditCheckRequest, 88 | context: _ServicerContext, 89 | ) -> typing.Union[authzed.api.v0.developer_pb2.EditCheckResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.EditCheckResponse]]: ... 90 | 91 | @abc.abstractmethod 92 | def Validate( 93 | self, 94 | request: authzed.api.v0.developer_pb2.ValidateRequest, 95 | context: _ServicerContext, 96 | ) -> typing.Union[authzed.api.v0.developer_pb2.ValidateResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.ValidateResponse]]: ... 97 | 98 | @abc.abstractmethod 99 | def Share( 100 | self, 101 | request: authzed.api.v0.developer_pb2.ShareRequest, 102 | context: _ServicerContext, 103 | ) -> typing.Union[authzed.api.v0.developer_pb2.ShareResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.ShareResponse]]: ... 104 | 105 | @abc.abstractmethod 106 | def LookupShared( 107 | self, 108 | request: authzed.api.v0.developer_pb2.LookupShareRequest, 109 | context: _ServicerContext, 110 | ) -> typing.Union[authzed.api.v0.developer_pb2.LookupShareResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.LookupShareResponse]]: ... 111 | 112 | @abc.abstractmethod 113 | def UpgradeSchema( 114 | self, 115 | request: authzed.api.v0.developer_pb2.UpgradeSchemaRequest, 116 | context: _ServicerContext, 117 | ) -> typing.Union[authzed.api.v0.developer_pb2.UpgradeSchemaResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.UpgradeSchemaResponse]]: ... 118 | 119 | @abc.abstractmethod 120 | def FormatSchema( 121 | self, 122 | request: authzed.api.v0.developer_pb2.FormatSchemaRequest, 123 | context: _ServicerContext, 124 | ) -> typing.Union[authzed.api.v0.developer_pb2.FormatSchemaResponse, collections.abc.Awaitable[authzed.api.v0.developer_pb2.FormatSchemaResponse]]: ... 125 | 126 | def add_DeveloperServiceServicer_to_server(servicer: DeveloperServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 127 | -------------------------------------------------------------------------------- /authzed/api/v1/__init__.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | from typing import Any, Callable 3 | 4 | import grpc 5 | import grpc.aio 6 | from grpc_interceptor import ClientCallDetails, ClientInterceptor 7 | 8 | from authzed.api.v1.core_pb2 import ( 9 | AlgebraicSubjectSet, 10 | ContextualizedCaveat, 11 | Cursor, 12 | DirectSubjectSet, 13 | ObjectReference, 14 | PermissionRelationshipTree, 15 | Relationship, 16 | RelationshipUpdate, 17 | SubjectReference, 18 | ZedToken, 19 | ) 20 | from authzed.api.v1.error_reason_pb2 import ErrorReason 21 | from authzed.api.v1.experimental_service_pb2 import ( 22 | BulkCheckPermissionPair, 23 | BulkCheckPermissionRequest, 24 | BulkCheckPermissionRequestItem, 25 | BulkCheckPermissionResponse, 26 | BulkCheckPermissionResponseItem, 27 | BulkExportRelationshipsRequest, 28 | BulkExportRelationshipsResponse, 29 | BulkImportRelationshipsRequest, 30 | BulkImportRelationshipsResponse, 31 | ) 32 | from authzed.api.v1.experimental_service_pb2_grpc import ExperimentalServiceStub 33 | from authzed.api.v1.permission_service_pb2 import ( 34 | CheckBulkPermissionsPair, 35 | CheckBulkPermissionsRequest, 36 | CheckBulkPermissionsRequestItem, 37 | CheckBulkPermissionsResponse, 38 | CheckBulkPermissionsResponseItem, 39 | CheckPermissionRequest, 40 | CheckPermissionResponse, 41 | Consistency, 42 | DeleteRelationshipsRequest, 43 | DeleteRelationshipsResponse, 44 | ExpandPermissionTreeRequest, 45 | ExpandPermissionTreeResponse, 46 | LookupResourcesRequest, 47 | LookupResourcesResponse, 48 | LookupSubjectsRequest, 49 | LookupSubjectsResponse, 50 | Precondition, 51 | ReadRelationshipsRequest, 52 | ReadRelationshipsResponse, 53 | RelationshipFilter, 54 | SubjectFilter, 55 | WriteRelationshipsRequest, 56 | WriteRelationshipsResponse, 57 | ) 58 | from authzed.api.v1.permission_service_pb2_grpc import PermissionsServiceStub 59 | from authzed.api.v1.schema_service_pb2 import ( 60 | ReadSchemaRequest, 61 | ReadSchemaResponse, 62 | WriteSchemaRequest, 63 | WriteSchemaResponse, 64 | ) 65 | from authzed.api.v1.schema_service_pb2_grpc import SchemaServiceStub 66 | from authzed.api.v1.watch_service_pb2 import WatchRequest, WatchResponse 67 | from authzed.api.v1.watch_service_pb2_grpc import WatchServiceStub 68 | 69 | 70 | class Client(SchemaServiceStub, PermissionsServiceStub, ExperimentalServiceStub, WatchServiceStub): 71 | """ 72 | v1 Authzed gRPC API client - Auto-detects sync or async depending on if initialized within an event loop 73 | """ 74 | 75 | def __init__(self, target, credentials, options=None, compression=None): 76 | channel = self.create_channel(target, credentials, options, compression) 77 | self.init_stubs(channel) 78 | 79 | def init_stubs(self, channel): 80 | SchemaServiceStub.__init__(self, channel) 81 | PermissionsServiceStub.__init__(self, channel) 82 | ExperimentalServiceStub.__init__(self, channel) 83 | WatchServiceStub.__init__(self, channel) 84 | 85 | def create_channel(self, target, credentials, options=None, compression=None): 86 | try: 87 | asyncio.get_running_loop() 88 | channelfn = grpc.aio.secure_channel 89 | except RuntimeError: 90 | channelfn = grpc.secure_channel 91 | 92 | return channelfn(target, credentials, options, compression) 93 | 94 | 95 | class AsyncClient(Client): 96 | """ 97 | v1 Authzed gRPC API client, for use with asyncio. 98 | """ 99 | 100 | def __init__(self, target, credentials, options=None, compression=None): 101 | channel = grpc.aio.secure_channel(target, credentials, options, compression) 102 | self.init_stubs(channel) 103 | 104 | 105 | class SyncClient(Client): 106 | """ 107 | v1 Authzed gRPC API client, running synchronously. 108 | """ 109 | 110 | def __init__(self, target, credentials, options=None, compression=None): 111 | channel = grpc.secure_channel(target, credentials, options, compression) 112 | self.init_stubs(channel) 113 | 114 | 115 | class TokenAuthorization(ClientInterceptor): 116 | def __init__(self, token: str): 117 | self._token = token 118 | 119 | def intercept( 120 | self, 121 | method: Callable, 122 | request_or_iterator: Any, 123 | call_details: grpc.ClientCallDetails, 124 | ): 125 | metadata: list[tuple[str, str | bytes]] = [("authorization", f"Bearer {self._token}")] 126 | if call_details.metadata is not None: 127 | metadata = [*metadata, *call_details.metadata] 128 | 129 | new_details = ClientCallDetails( 130 | call_details.method, 131 | call_details.timeout, 132 | metadata, 133 | call_details.credentials, 134 | call_details.wait_for_ready, 135 | call_details.compression, 136 | ) 137 | 138 | return method(request_or_iterator, new_details) 139 | 140 | 141 | class InsecureClient(Client): 142 | """ 143 | An insecure client variant for non-TLS contexts. 144 | 145 | The default behavior of the python gRPC client is to restrict non-TLS 146 | calls to `localhost` only, which is frustrating in contexts like docker-compose, 147 | so we provide this as a convenience. 148 | """ 149 | 150 | def __init__( 151 | self, 152 | target: str, 153 | token: str, 154 | options=None, 155 | compression=None, 156 | ): 157 | fake_credentials = grpc.local_channel_credentials() 158 | channel = self.create_channel(target, fake_credentials, options, compression) 159 | auth_interceptor = TokenAuthorization(token) 160 | 161 | insecure_channel = grpc.insecure_channel(target, options, compression) 162 | channel = grpc.intercept_channel(insecure_channel, auth_interceptor) 163 | 164 | self.init_stubs(channel) 165 | 166 | 167 | __all__ = [ 168 | "Client", 169 | # Core 170 | "AlgebraicSubjectSet", 171 | "ContextualizedCaveat", 172 | "DirectSubjectSet", 173 | "ObjectReference", 174 | "PermissionRelationshipTree", 175 | "Relationship", 176 | "RelationshipUpdate", 177 | "SubjectReference", 178 | "ZedToken", 179 | # Error Reason 180 | "ErrorReason", 181 | # Permission Service 182 | "CheckBulkPermissionsPair", 183 | "CheckBulkPermissionsRequest", 184 | "CheckBulkPermissionsRequestItem", 185 | "CheckBulkPermissionsResponse", 186 | "CheckBulkPermissionsResponseItem", 187 | "CheckPermissionRequest", 188 | "CheckPermissionResponse", 189 | "Consistency", 190 | "Cursor", 191 | "DeleteRelationshipsRequest", 192 | "DeleteRelationshipsResponse", 193 | "ExpandPermissionTreeRequest", 194 | "ExpandPermissionTreeResponse", 195 | "InsecureClient", 196 | "LookupResourcesRequest", 197 | "LookupResourcesResponse", 198 | "LookupSubjectsRequest", 199 | "LookupSubjectsResponse", 200 | "Precondition", 201 | "ReadRelationshipsRequest", 202 | "ReadRelationshipsResponse", 203 | "RelationshipFilter", 204 | "SubjectFilter", 205 | "WriteRelationshipsRequest", 206 | "WriteRelationshipsResponse", 207 | # Schema Service 208 | "ReadSchemaRequest", 209 | "ReadSchemaResponse", 210 | "WriteSchemaRequest", 211 | "WriteSchemaResponse", 212 | # Watch Service 213 | "WatchRequest", 214 | "WatchResponse", 215 | # Experimental Service 216 | "BulkCheckPermissionRequest", 217 | "BulkCheckPermissionResponse", 218 | "BulkCheckPermissionPair", 219 | "BulkCheckPermissionRequestItem", 220 | "BulkCheckPermissionResponseItem", 221 | "BulkImportRelationshipsRequest", 222 | "BulkImportRelationshipsResponse", 223 | "BulkExportRelationshipsRequest", 224 | "BulkExportRelationshipsResponse", 225 | ] 226 | -------------------------------------------------------------------------------- /authzed/api/v1/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Any, Optional, Sequence, Tuple 2 | 3 | import grpc 4 | 5 | from authzed.api.v1.core_pb2 import ( 6 | AlgebraicSubjectSet, 7 | ContextualizedCaveat, 8 | Cursor, 9 | DirectSubjectSet, 10 | ObjectReference, 11 | PermissionRelationshipTree, 12 | Relationship, 13 | RelationshipUpdate, 14 | SubjectReference, 15 | ZedToken, 16 | ) 17 | from authzed.api.v1.error_reason_pb2 import ErrorReason 18 | from authzed.api.v1.experimental_service_pb2 import ( 19 | BulkCheckPermissionPair, 20 | BulkCheckPermissionRequest, 21 | BulkCheckPermissionRequestItem, 22 | BulkCheckPermissionResponse, 23 | BulkCheckPermissionResponseItem, 24 | BulkExportRelationshipsRequest, 25 | BulkExportRelationshipsResponse, 26 | BulkImportRelationshipsRequest, 27 | BulkImportRelationshipsResponse, 28 | ) 29 | from authzed.api.v1.experimental_service_pb2_grpc import ( 30 | ExperimentalServiceAsyncStub, 31 | ExperimentalServiceStub, 32 | ) 33 | from authzed.api.v1.permission_service_pb2 import ( 34 | CheckBulkPermissionsPair, 35 | CheckBulkPermissionsRequest, 36 | CheckBulkPermissionsRequestItem, 37 | CheckBulkPermissionsResponse, 38 | CheckBulkPermissionsResponseItem, 39 | CheckPermissionRequest, 40 | CheckPermissionResponse, 41 | Consistency, 42 | DeleteRelationshipsRequest, 43 | DeleteRelationshipsResponse, 44 | ExpandPermissionTreeRequest, 45 | ExpandPermissionTreeResponse, 46 | LookupResourcesRequest, 47 | LookupResourcesResponse, 48 | LookupSubjectsRequest, 49 | LookupSubjectsResponse, 50 | Precondition, 51 | ReadRelationshipsRequest, 52 | ReadRelationshipsResponse, 53 | RelationshipFilter, 54 | SubjectFilter, 55 | WriteRelationshipsRequest, 56 | WriteRelationshipsResponse, 57 | ) 58 | from authzed.api.v1.permission_service_pb2_grpc import ( 59 | PermissionsServiceAsyncStub, 60 | PermissionsServiceStub, 61 | ) 62 | from authzed.api.v1.schema_service_pb2 import ( 63 | ReadSchemaRequest, 64 | ReadSchemaResponse, 65 | WriteSchemaRequest, 66 | WriteSchemaResponse, 67 | ) 68 | from authzed.api.v1.schema_service_pb2_grpc import SchemaServiceAsyncStub, SchemaServiceStub 69 | from authzed.api.v1.watch_service_pb2 import WatchRequest, WatchResponse 70 | from authzed.api.v1.watch_service_pb2_grpc import WatchServiceAsyncStub, WatchServiceStub 71 | 72 | class Client(SchemaServiceStub, PermissionsServiceStub, ExperimentalServiceStub, WatchServiceStub): 73 | """The Client is typed as a synchronous client (though in practice it works with both sync and async code). 74 | If you are using the async code, you should switch to the AsyncClient class instead in order to get proper type hints 75 | """ 76 | 77 | def __init__( 78 | self, 79 | target: str, 80 | credentials: grpc.ChannelCredentials, 81 | options: Optional[Sequence[Tuple[str, Any]]] = None, 82 | compression: Optional[grpc.Compression] = None, 83 | ) -> None: ... 84 | 85 | class SyncClient( 86 | SchemaServiceStub, PermissionsServiceStub, ExperimentalServiceStub, WatchServiceStub 87 | ): 88 | def __init__( 89 | self, 90 | target: str, 91 | credentials: grpc.ChannelCredentials, 92 | options: Optional[Sequence[Tuple[str, Any]]] = None, 93 | compression: Optional[grpc.Compression] = None, 94 | ) -> None: ... 95 | 96 | class AsyncClient( 97 | SchemaServiceAsyncStub, 98 | PermissionsServiceAsyncStub, 99 | ExperimentalServiceAsyncStub, 100 | WatchServiceAsyncStub, 101 | ): 102 | def __init__( 103 | self, 104 | target: str, 105 | credentials: grpc.ChannelCredentials, 106 | options: Optional[Sequence[Tuple[str, Any]]] = None, 107 | compression: Optional[grpc.Compression] = None, 108 | ) -> None: ... 109 | 110 | class InsecureClient(Client): 111 | def __init__( 112 | self, 113 | target: str, 114 | token: str, 115 | options=None, 116 | compression=None, 117 | ) -> None: ... 118 | 119 | __all__ = [ 120 | "Client", 121 | # Core 122 | "AlgebraicSubjectSet", 123 | "ContextualizedCaveat", 124 | "DirectSubjectSet", 125 | "ObjectReference", 126 | "PermissionRelationshipTree", 127 | "Relationship", 128 | "RelationshipUpdate", 129 | "SubjectReference", 130 | "ZedToken", 131 | # Error Reason 132 | "ErrorReason", 133 | # Permission Service 134 | "CheckBulkPermissionsPair", 135 | "CheckBulkPermissionsRequest", 136 | "CheckBulkPermissionsRequestItem", 137 | "CheckBulkPermissionsResponse", 138 | "CheckBulkPermissionsResponseItem", 139 | "CheckPermissionRequest", 140 | "CheckPermissionResponse", 141 | "Consistency", 142 | "Cursor", 143 | "DeleteRelationshipsRequest", 144 | "DeleteRelationshipsResponse", 145 | "ExpandPermissionTreeRequest", 146 | "ExpandPermissionTreeResponse", 147 | "InsecureClient", 148 | "LookupResourcesRequest", 149 | "LookupResourcesResponse", 150 | "LookupSubjectsRequest", 151 | "LookupSubjectsResponse", 152 | "Precondition", 153 | "ReadRelationshipsRequest", 154 | "ReadRelationshipsResponse", 155 | "RelationshipFilter", 156 | "SubjectFilter", 157 | "WriteRelationshipsRequest", 158 | "WriteRelationshipsResponse", 159 | # Schema Service 160 | "ReadSchemaRequest", 161 | "ReadSchemaResponse", 162 | "WriteSchemaRequest", 163 | "WriteSchemaResponse", 164 | # Watch Service 165 | "WatchRequest", 166 | "WatchResponse", 167 | # Experimental Service 168 | "BulkCheckPermissionRequest", 169 | "BulkCheckPermissionResponse", 170 | "BulkCheckPermissionPair", 171 | "BulkCheckPermissionRequestItem", 172 | "BulkCheckPermissionResponseItem", 173 | "BulkImportRelationshipsRequest", 174 | "BulkImportRelationshipsResponse", 175 | "BulkExportRelationshipsRequest", 176 | "BulkExportRelationshipsResponse", 177 | ] 178 | -------------------------------------------------------------------------------- /authzed/api/v1/core_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /authzed/api/v1/core_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import collections.abc 8 | import grpc 9 | import grpc.aio 10 | import typing 11 | 12 | _T = typing.TypeVar("_T") 13 | 14 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 15 | 16 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 17 | ... 18 | -------------------------------------------------------------------------------- /authzed/api/v1/debug_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v1/debug.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v1/debug.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v1 import core_pb2 as authzed_dot_api_dot_v1_dot_core__pb2 26 | from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 27 | from google.protobuf import duration_pb2 as google_dot_protobuf_dot_duration__pb2 28 | from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 29 | from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 30 | from validate import validate_pb2 as validate_dot_validate__pb2 31 | 32 | 33 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1a\x61uthzed/api/v1/debug.proto\x12\x0e\x61uthzed.api.v1\x1a\x19\x61uthzed/api/v1/core.proto\x1a\x1b\x62uf/validate/validate.proto\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x17validate/validate.proto\"j\n\x10\x44\x65\x62ugInformation\x12\x35\n\x05\x63heck\x18\x01 \x01(\x0b\x32\x1f.authzed.api.v1.CheckDebugTraceR\x05\x63heck\x12\x1f\n\x0bschema_used\x18\x02 \x01(\tR\nschemaUsed\"\xaa\t\n\x0f\x43heckDebugTrace\x12K\n\x08resource\x18\x01 \x01(\x0b\x32\x1f.authzed.api.v1.ObjectReferenceB\x0e\xfa\x42\x05\x8a\x01\x02\x10\x01\xbaH\x03\xc8\x01\x01R\x08resource\x12\x1e\n\npermission\x18\x02 \x01(\tR\npermission\x12m\n\x0fpermission_type\x18\x03 \x01(\x0e\x32..authzed.api.v1.CheckDebugTrace.PermissionTypeB\x14\xfa\x42\x07\x82\x01\x04\x10\x01 \x00\xbaH\x07\x82\x01\x04\x10\x01 \x00R\x0epermissionType\x12J\n\x07subject\x18\x04 \x01(\x0b\x32 .authzed.api.v1.SubjectReferenceB\x0e\xfa\x42\x05\x8a\x01\x02\x10\x01\xbaH\x03\xc8\x01\x01R\x07subject\x12\\\n\x06result\x18\x05 \x01(\x0e\x32..authzed.api.v1.CheckDebugTrace.PermissionshipB\x14\xfa\x42\x07\x82\x01\x04\x10\x01 \x00\xbaH\x07\x82\x01\x04\x10\x01 \x00R\x06result\x12T\n\x16\x63\x61veat_evaluation_info\x18\x08 \x01(\x0b\x32\x1e.authzed.api.v1.CaveatEvalInfoR\x14\x63\x61veatEvaluationInfo\x12\x35\n\x08\x64uration\x18\t \x01(\x0b\x32\x19.google.protobuf.DurationR\x08\x64uration\x12,\n\x11was_cached_result\x18\x06 \x01(\x08H\x00R\x0fwasCachedResult\x12P\n\x0csub_problems\x18\x07 \x01(\x0b\x32+.authzed.api.v1.CheckDebugTrace.SubProblemsH\x00R\x0bsubProblems\x12J\n\x13optional_expires_at\x18\n \x01(\x0b\x32\x1a.google.protobuf.TimestampR\x11optionalExpiresAt\x12,\n\x12trace_operation_id\x18\x0b \x01(\tR\x10traceOperationId\x12\x16\n\x06source\x18\x0c \x01(\tR\x06source\x1a\x46\n\x0bSubProblems\x12\x37\n\x06traces\x18\x01 \x03(\x0b\x32\x1f.authzed.api.v1.CheckDebugTraceR\x06traces\"o\n\x0ePermissionType\x12\x1f\n\x1bPERMISSION_TYPE_UNSPECIFIED\x10\x00\x12\x1c\n\x18PERMISSION_TYPE_RELATION\x10\x01\x12\x1e\n\x1aPERMISSION_TYPE_PERMISSION\x10\x02\"\xa0\x01\n\x0ePermissionship\x12\x1e\n\x1aPERMISSIONSHIP_UNSPECIFIED\x10\x00\x12 \n\x1cPERMISSIONSHIP_NO_PERMISSION\x10\x01\x12!\n\x1dPERMISSIONSHIP_HAS_PERMISSION\x10\x02\x12)\n%PERMISSIONSHIP_CONDITIONAL_PERMISSION\x10\x03\x42\x16\n\nresolution\x12\x08\xf8\x42\x01\xbaH\x02\x08\x01\"\x94\x03\n\x0e\x43\x61veatEvalInfo\x12\x1e\n\nexpression\x18\x01 \x01(\tR\nexpression\x12=\n\x06result\x18\x02 \x01(\x0e\x32%.authzed.api.v1.CaveatEvalInfo.ResultR\x06result\x12\x31\n\x07\x63ontext\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x07\x63ontext\x12Q\n\x13partial_caveat_info\x18\x04 \x01(\x0b\x32!.authzed.api.v1.PartialCaveatInfoR\x11partialCaveatInfo\x12\x1f\n\x0b\x63\x61veat_name\x18\x05 \x01(\tR\ncaveatName\"|\n\x06Result\x12\x16\n\x12RESULT_UNSPECIFIED\x10\x00\x12\x16\n\x12RESULT_UNEVALUATED\x10\x01\x12\x10\n\x0cRESULT_FALSE\x10\x02\x12\x0f\n\x0bRESULT_TRUE\x10\x03\x12\x1f\n\x1bRESULT_MISSING_SOME_CONTEXT\x10\x04\x42J\n\x12\x63om.authzed.api.v1P\x01Z2github.com/authzed/authzed-go/proto/authzed/api/v1b\x06proto3') 34 | 35 | _globals = globals() 36 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 37 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v1.debug_pb2', _globals) 38 | if not _descriptor._USE_C_DESCRIPTORS: 39 | _globals['DESCRIPTOR']._loaded_options = None 40 | _globals['DESCRIPTOR']._serialized_options = b'\n\022com.authzed.api.v1P\001Z2github.com/authzed/authzed-go/proto/authzed/api/v1' 41 | _globals['_CHECKDEBUGTRACE'].oneofs_by_name['resolution']._loaded_options = None 42 | _globals['_CHECKDEBUGTRACE'].oneofs_by_name['resolution']._serialized_options = b'\370B\001\272H\002\010\001' 43 | _globals['_CHECKDEBUGTRACE'].fields_by_name['resource']._loaded_options = None 44 | _globals['_CHECKDEBUGTRACE'].fields_by_name['resource']._serialized_options = b'\372B\005\212\001\002\020\001\272H\003\310\001\001' 45 | _globals['_CHECKDEBUGTRACE'].fields_by_name['permission_type']._loaded_options = None 46 | _globals['_CHECKDEBUGTRACE'].fields_by_name['permission_type']._serialized_options = b'\372B\007\202\001\004\020\001 \000\272H\007\202\001\004\020\001 \000' 47 | _globals['_CHECKDEBUGTRACE'].fields_by_name['subject']._loaded_options = None 48 | _globals['_CHECKDEBUGTRACE'].fields_by_name['subject']._serialized_options = b'\372B\005\212\001\002\020\001\272H\003\310\001\001' 49 | _globals['_CHECKDEBUGTRACE'].fields_by_name['result']._loaded_options = None 50 | _globals['_CHECKDEBUGTRACE'].fields_by_name['result']._serialized_options = b'\372B\007\202\001\004\020\001 \000\272H\007\202\001\004\020\001 \000' 51 | _globals['_DEBUGINFORMATION']._serialized_start=222 52 | _globals['_DEBUGINFORMATION']._serialized_end=328 53 | _globals['_CHECKDEBUGTRACE']._serialized_start=331 54 | _globals['_CHECKDEBUGTRACE']._serialized_end=1525 55 | _globals['_CHECKDEBUGTRACE_SUBPROBLEMS']._serialized_start=1155 56 | _globals['_CHECKDEBUGTRACE_SUBPROBLEMS']._serialized_end=1225 57 | _globals['_CHECKDEBUGTRACE_PERMISSIONTYPE']._serialized_start=1227 58 | _globals['_CHECKDEBUGTRACE_PERMISSIONTYPE']._serialized_end=1338 59 | _globals['_CHECKDEBUGTRACE_PERMISSIONSHIP']._serialized_start=1341 60 | _globals['_CHECKDEBUGTRACE_PERMISSIONSHIP']._serialized_end=1501 61 | _globals['_CAVEATEVALINFO']._serialized_start=1528 62 | _globals['_CAVEATEVALINFO']._serialized_end=1932 63 | _globals['_CAVEATEVALINFO_RESULT']._serialized_start=1808 64 | _globals['_CAVEATEVALINFO_RESULT']._serialized_end=1932 65 | # @@protoc_insertion_point(module_scope) 66 | -------------------------------------------------------------------------------- /authzed/api/v1/debug_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /authzed/api/v1/debug_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import collections.abc 8 | import grpc 9 | import grpc.aio 10 | import typing 11 | 12 | _T = typing.TypeVar("_T") 13 | 14 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 15 | 16 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 17 | ... 18 | -------------------------------------------------------------------------------- /authzed/api/v1/error_reason_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v1/error_reason.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v1/error_reason.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | 26 | 27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!authzed/api/v1/error_reason.proto\x12\x0e\x61uthzed.api.v1*\xa2\n\n\x0b\x45rrorReason\x12\x1c\n\x18\x45RROR_REASON_UNSPECIFIED\x10\x00\x12#\n\x1f\x45RROR_REASON_SCHEMA_PARSE_ERROR\x10\x01\x12\"\n\x1e\x45RROR_REASON_SCHEMA_TYPE_ERROR\x10\x02\x12#\n\x1f\x45RROR_REASON_UNKNOWN_DEFINITION\x10\x03\x12/\n+ERROR_REASON_UNKNOWN_RELATION_OR_PERMISSION\x10\x04\x12,\n(ERROR_REASON_TOO_MANY_UPDATES_IN_REQUEST\x10\x05\x12\x32\n.ERROR_REASON_TOO_MANY_PRECONDITIONS_IN_REQUEST\x10\x06\x12\x35\n1ERROR_REASON_WRITE_OR_DELETE_PRECONDITION_FAILURE\x10\x07\x12\"\n\x1e\x45RROR_REASON_SERVICE_READ_ONLY\x10\x08\x12\x1f\n\x1b\x45RROR_REASON_UNKNOWN_CAVEAT\x10\t\x12%\n!ERROR_REASON_INVALID_SUBJECT_TYPE\x10\n\x12,\n(ERROR_REASON_CAVEAT_PARAMETER_TYPE_ERROR\x10\x0b\x12-\n)ERROR_REASON_UPDATES_ON_SAME_RELATIONSHIP\x10\x0c\x12)\n%ERROR_REASON_CANNOT_UPDATE_PERMISSION\x10\r\x12(\n$ERROR_REASON_CAVEAT_EVALUATION_ERROR\x10\x0e\x12\x1f\n\x1b\x45RROR_REASON_INVALID_CURSOR\x10\x0f\x12@\n\x1a\rAuthorization \x02\x62\x10\n\x0e\n\nApiKeyAuth\x12\x00rE\n\x1bMore about the Authzed API.\x12&https://docs.authzed.com/reference/apib\x06proto3') 29 | 30 | _globals = globals() 31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v1.openapi_pb2', _globals) 33 | if not _descriptor._USE_C_DESCRIPTORS: 34 | _globals['DESCRIPTOR']._loaded_options = None 35 | _globals['DESCRIPTOR']._serialized_options = b'\n\022com.authzed.api.v1P\001Z2github.com/authzed/authzed-go/proto/authzed/api/v1\222A\211\003\022\234\001\n\007Authzed\"D\n\rAuthzed, Inc.\022\036https://github.com/authzed/api\032\023support@authzed.com*F\n\022Apache 2.0 License\0220https://github.com/authzed/api/blob/main/LICENSE2\0031.0*\003\001\002\0042\020application/json:\020application/jsonZf\nd\n\nApiKeyAuth\022V\010\002\022ASpiceDB preshared-key, prefixed by Bearer: Bearer \032\rAuthorization \002b\020\n\016\n\nApiKeyAuth\022\000rE\n\033More about the Authzed API.\022&https://docs.authzed.com/reference/api' 36 | # @@protoc_insertion_point(module_scope) 37 | -------------------------------------------------------------------------------- /authzed/api/v1/openapi_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import google.protobuf.descriptor 7 | 8 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 9 | -------------------------------------------------------------------------------- /authzed/api/v1/openapi_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /authzed/api/v1/openapi_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import collections.abc 8 | import grpc 9 | import grpc.aio 10 | import typing 11 | 12 | _T = typing.TypeVar("_T") 13 | 14 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 15 | 16 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 17 | ... 18 | -------------------------------------------------------------------------------- /authzed/api/v1/schema_service_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.v1.schema_service_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class SchemaServiceStub: 21 | """SchemaService implements operations on a Permissions System's Schema.""" 22 | 23 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 24 | ReadSchema: grpc.UnaryUnaryMultiCallable[ 25 | authzed.api.v1.schema_service_pb2.ReadSchemaRequest, 26 | authzed.api.v1.schema_service_pb2.ReadSchemaResponse, 27 | ] 28 | """Read returns the current Object Definitions for a Permissions System. 29 | 30 | Errors include: 31 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 32 | - NOT_FOUND: no schema has been defined 33 | """ 34 | 35 | WriteSchema: grpc.UnaryUnaryMultiCallable[ 36 | authzed.api.v1.schema_service_pb2.WriteSchemaRequest, 37 | authzed.api.v1.schema_service_pb2.WriteSchemaResponse, 38 | ] 39 | """Write overwrites the current Object Definitions for a Permissions System.""" 40 | 41 | class SchemaServiceAsyncStub: 42 | """SchemaService implements operations on a Permissions System's Schema.""" 43 | 44 | ReadSchema: grpc.aio.UnaryUnaryMultiCallable[ 45 | authzed.api.v1.schema_service_pb2.ReadSchemaRequest, 46 | authzed.api.v1.schema_service_pb2.ReadSchemaResponse, 47 | ] 48 | """Read returns the current Object Definitions for a Permissions System. 49 | 50 | Errors include: 51 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 52 | - NOT_FOUND: no schema has been defined 53 | """ 54 | 55 | WriteSchema: grpc.aio.UnaryUnaryMultiCallable[ 56 | authzed.api.v1.schema_service_pb2.WriteSchemaRequest, 57 | authzed.api.v1.schema_service_pb2.WriteSchemaResponse, 58 | ] 59 | """Write overwrites the current Object Definitions for a Permissions System.""" 60 | 61 | class SchemaServiceServicer(metaclass=abc.ABCMeta): 62 | """SchemaService implements operations on a Permissions System's Schema.""" 63 | 64 | @abc.abstractmethod 65 | def ReadSchema( 66 | self, 67 | request: authzed.api.v1.schema_service_pb2.ReadSchemaRequest, 68 | context: _ServicerContext, 69 | ) -> typing.Union[authzed.api.v1.schema_service_pb2.ReadSchemaResponse, collections.abc.Awaitable[authzed.api.v1.schema_service_pb2.ReadSchemaResponse]]: 70 | """Read returns the current Object Definitions for a Permissions System. 71 | 72 | Errors include: 73 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 74 | - NOT_FOUND: no schema has been defined 75 | """ 76 | 77 | @abc.abstractmethod 78 | def WriteSchema( 79 | self, 80 | request: authzed.api.v1.schema_service_pb2.WriteSchemaRequest, 81 | context: _ServicerContext, 82 | ) -> typing.Union[authzed.api.v1.schema_service_pb2.WriteSchemaResponse, collections.abc.Awaitable[authzed.api.v1.schema_service_pb2.WriteSchemaResponse]]: 83 | """Write overwrites the current Object Definitions for a Permissions System.""" 84 | 85 | def add_SchemaServiceServicer_to_server(servicer: SchemaServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 86 | -------------------------------------------------------------------------------- /authzed/api/v1/watch_service_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v1/watch_service.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v1/watch_service.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v1 import core_pb2 as authzed_dot_api_dot_v1_dot_core__pb2 26 | from authzed.api.v1 import permission_service_pb2 as authzed_dot_api_dot_v1_dot_permission__service__pb2 27 | from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 28 | from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 29 | from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 30 | from validate import validate_pb2 as validate_dot_validate__pb2 31 | 32 | 33 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"authzed/api/v1/watch_service.proto\x12\x0e\x61uthzed.api.v1\x1a\x19\x61uthzed/api/v1/core.proto\x1a\'authzed/api/v1/permission_service.proto\x1a\x1b\x62uf/validate/validate.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x17validate/validate.proto\"\x9a\x03\n\x0cWatchRequest\x12\xd3\x01\n\x15optional_object_types\x18\x01 \x03(\tB\x9e\x01\xfa\x42L\x92\x01I\x08\x00\"ErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaHL\x92\x01I\x08\x00\"ErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$R\x13optionalObjectTypes\x12L\n\x15optional_start_cursor\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x13optionalStartCursor\x12\x66\n\x1doptional_relationship_filters\x18\x03 \x03(\x0b\x32\".authzed.api.v1.RelationshipFilterR\x1boptionalRelationshipFilters\"\xed\x01\n\rWatchResponse\x12<\n\x07updates\x18\x01 \x03(\x0b\x32\".authzed.api.v1.RelationshipUpdateR\x07updates\x12\x41\n\x0f\x63hanges_through\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x0e\x63hangesThrough\x12[\n\x1doptional_transaction_metadata\x18\x03 \x01(\x0b\x32\x17.google.protobuf.StructR\x1boptionalTransactionMetadata2l\n\x0cWatchService\x12\\\n\x05Watch\x12\x1c.authzed.api.v1.WatchRequest\x1a\x1d.authzed.api.v1.WatchResponse\"\x14\x82\xd3\xe4\x93\x02\x0e\"\t/v1/watch:\x01*0\x01\x42J\n\x12\x63om.authzed.api.v1P\x01Z2github.com/authzed/authzed-go/proto/authzed/api/v1b\x06proto3') 34 | 35 | _globals = globals() 36 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 37 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v1.watch_service_pb2', _globals) 38 | if not _descriptor._USE_C_DESCRIPTORS: 39 | _globals['DESCRIPTOR']._loaded_options = None 40 | _globals['DESCRIPTOR']._serialized_options = b'\n\022com.authzed.api.v1P\001Z2github.com/authzed/authzed-go/proto/authzed/api/v1' 41 | _globals['_WATCHREQUEST'].fields_by_name['optional_object_types']._loaded_options = None 42 | _globals['_WATCHREQUEST'].fields_by_name['optional_object_types']._serialized_options = b'\372BL\222\001I\010\000\"ErC(\200\0012>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\272HL\222\001I\010\000\"ErC(\200\0012>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$' 43 | _globals['_WATCHSERVICE'].methods_by_name['Watch']._loaded_options = None 44 | _globals['_WATCHSERVICE'].methods_by_name['Watch']._serialized_options = b'\202\323\344\223\002\016\"\t/v1/watch:\001*' 45 | _globals['_WATCHREQUEST']._serialized_start=237 46 | _globals['_WATCHREQUEST']._serialized_end=647 47 | _globals['_WATCHRESPONSE']._serialized_start=650 48 | _globals['_WATCHRESPONSE']._serialized_end=887 49 | _globals['_WATCHSERVICE']._serialized_start=889 50 | _globals['_WATCHSERVICE']._serialized_end=997 51 | # @@protoc_insertion_point(module_scope) 52 | -------------------------------------------------------------------------------- /authzed/api/v1/watch_service_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import authzed.api.v1.core_pb2 7 | import authzed.api.v1.permission_service_pb2 8 | import builtins 9 | import collections.abc 10 | import google.protobuf.descriptor 11 | import google.protobuf.internal.containers 12 | import google.protobuf.message 13 | import google.protobuf.struct_pb2 14 | import typing 15 | 16 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 17 | 18 | @typing.final 19 | class WatchRequest(google.protobuf.message.Message): 20 | """WatchRequest specifies the object definitions for which we want to start 21 | watching mutations, and an optional start snapshot for when to start 22 | watching. 23 | """ 24 | 25 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 26 | 27 | OPTIONAL_OBJECT_TYPES_FIELD_NUMBER: builtins.int 28 | OPTIONAL_START_CURSOR_FIELD_NUMBER: builtins.int 29 | OPTIONAL_RELATIONSHIP_FILTERS_FIELD_NUMBER: builtins.int 30 | @property 31 | def optional_object_types(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 32 | """optional_object_types is a filter of resource object types to watch for changes. 33 | If specified, only changes to the specified object types will be returned and 34 | optional_relationship_filters cannot be used. 35 | """ 36 | 37 | @property 38 | def optional_start_cursor(self) -> authzed.api.v1.core_pb2.ZedToken: 39 | """optional_start_cursor is the ZedToken holding the point-in-time at 40 | which to start watching for changes. 41 | If not specified, the watch will begin at the current head revision 42 | of the datastore, returning any updates that occur after the caller 43 | makes the request. 44 | Note that if this cursor references a point-in-time containing data 45 | that has been garbage collected, an error will be returned. 46 | """ 47 | 48 | @property 49 | def optional_relationship_filters(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[authzed.api.v1.permission_service_pb2.RelationshipFilter]: 50 | """optional_relationship_filters, if specified, indicates the 51 | filter(s) to apply to each relationship to be returned by watch. 52 | The relationship will be returned as long as at least one filter matches, 53 | this allows clients to match relationships on multiple filters on a single watch call. 54 | If specified, optional_object_types cannot be used. 55 | """ 56 | 57 | def __init__( 58 | self, 59 | *, 60 | optional_object_types: collections.abc.Iterable[builtins.str] | None = ..., 61 | optional_start_cursor: authzed.api.v1.core_pb2.ZedToken | None = ..., 62 | optional_relationship_filters: collections.abc.Iterable[authzed.api.v1.permission_service_pb2.RelationshipFilter] | None = ..., 63 | ) -> None: ... 64 | def HasField(self, field_name: typing.Literal["optional_start_cursor", b"optional_start_cursor"]) -> builtins.bool: ... 65 | def ClearField(self, field_name: typing.Literal["optional_object_types", b"optional_object_types", "optional_relationship_filters", b"optional_relationship_filters", "optional_start_cursor", b"optional_start_cursor"]) -> None: ... 66 | 67 | global___WatchRequest = WatchRequest 68 | 69 | @typing.final 70 | class WatchResponse(google.protobuf.message.Message): 71 | """WatchResponse contains all tuple modification events in ascending 72 | timestamp order, from the requested start snapshot to a snapshot 73 | encoded in the watch response. The client can use the snapshot to resume 74 | watching where the previous watch response left off. 75 | """ 76 | 77 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 78 | 79 | UPDATES_FIELD_NUMBER: builtins.int 80 | CHANGES_THROUGH_FIELD_NUMBER: builtins.int 81 | OPTIONAL_TRANSACTION_METADATA_FIELD_NUMBER: builtins.int 82 | @property 83 | def updates(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[authzed.api.v1.core_pb2.RelationshipUpdate]: 84 | """updates are the RelationshipUpdate events that have occurred since the 85 | last watch response. 86 | """ 87 | 88 | @property 89 | def changes_through(self) -> authzed.api.v1.core_pb2.ZedToken: 90 | """changes_through is the ZedToken that represents the point in time 91 | that the watch response is current through. This token can be used 92 | in a subsequent WatchRequest to resume watching from this point. 93 | """ 94 | 95 | @property 96 | def optional_transaction_metadata(self) -> google.protobuf.struct_pb2.Struct: 97 | """optional_transaction_metadata is an optional field that returns the transaction metadata 98 | given to SpiceDB during the transaction that produced the changes in this response. 99 | This field may not exist if no transaction metadata was provided. 100 | """ 101 | 102 | def __init__( 103 | self, 104 | *, 105 | updates: collections.abc.Iterable[authzed.api.v1.core_pb2.RelationshipUpdate] | None = ..., 106 | changes_through: authzed.api.v1.core_pb2.ZedToken | None = ..., 107 | optional_transaction_metadata: google.protobuf.struct_pb2.Struct | None = ..., 108 | ) -> None: ... 109 | def HasField(self, field_name: typing.Literal["changes_through", b"changes_through", "optional_transaction_metadata", b"optional_transaction_metadata"]) -> builtins.bool: ... 110 | def ClearField(self, field_name: typing.Literal["changes_through", b"changes_through", "optional_transaction_metadata", b"optional_transaction_metadata", "updates", b"updates"]) -> None: ... 111 | 112 | global___WatchResponse = WatchResponse 113 | -------------------------------------------------------------------------------- /authzed/api/v1/watch_service_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | from authzed.api.v1 import watch_service_pb2 as authzed_dot_api_dot_v1_dot_watch__service__pb2 6 | 7 | 8 | class WatchServiceStub(object): 9 | """Missing associated documentation comment in .proto file.""" 10 | 11 | def __init__(self, channel): 12 | """Constructor. 13 | 14 | Args: 15 | channel: A grpc.Channel. 16 | """ 17 | self.Watch = channel.unary_stream( 18 | '/authzed.api.v1.WatchService/Watch', 19 | request_serializer=authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchRequest.SerializeToString, 20 | response_deserializer=authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchResponse.FromString, 21 | _registered_method=True) 22 | 23 | 24 | class WatchServiceServicer(object): 25 | """Missing associated documentation comment in .proto file.""" 26 | 27 | def Watch(self, request, context): 28 | """Missing associated documentation comment in .proto file.""" 29 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 30 | context.set_details('Method not implemented!') 31 | raise NotImplementedError('Method not implemented!') 32 | 33 | 34 | def add_WatchServiceServicer_to_server(servicer, server): 35 | rpc_method_handlers = { 36 | 'Watch': grpc.unary_stream_rpc_method_handler( 37 | servicer.Watch, 38 | request_deserializer=authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchRequest.FromString, 39 | response_serializer=authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchResponse.SerializeToString, 40 | ), 41 | } 42 | generic_handler = grpc.method_handlers_generic_handler( 43 | 'authzed.api.v1.WatchService', rpc_method_handlers) 44 | server.add_generic_rpc_handlers((generic_handler,)) 45 | server.add_registered_method_handlers('authzed.api.v1.WatchService', rpc_method_handlers) 46 | 47 | 48 | # This class is part of an EXPERIMENTAL API. 49 | class WatchService(object): 50 | """Missing associated documentation comment in .proto file.""" 51 | 52 | @staticmethod 53 | def Watch(request, 54 | target, 55 | options=(), 56 | channel_credentials=None, 57 | call_credentials=None, 58 | insecure=False, 59 | compression=None, 60 | wait_for_ready=None, 61 | timeout=None, 62 | metadata=None): 63 | return grpc.experimental.unary_stream( 64 | request, 65 | target, 66 | '/authzed.api.v1.WatchService/Watch', 67 | authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchRequest.SerializeToString, 68 | authzed_dot_api_dot_v1_dot_watch__service__pb2.WatchResponse.FromString, 69 | options, 70 | channel_credentials, 71 | insecure, 72 | call_credentials, 73 | compression, 74 | wait_for_ready, 75 | timeout, 76 | metadata, 77 | _registered_method=True) 78 | -------------------------------------------------------------------------------- /authzed/api/v1/watch_service_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.v1.watch_service_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class WatchServiceStub: 21 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 22 | Watch: grpc.UnaryStreamMultiCallable[ 23 | authzed.api.v1.watch_service_pb2.WatchRequest, 24 | authzed.api.v1.watch_service_pb2.WatchResponse, 25 | ] 26 | 27 | class WatchServiceAsyncStub: 28 | Watch: grpc.aio.UnaryStreamMultiCallable[ 29 | authzed.api.v1.watch_service_pb2.WatchRequest, 30 | authzed.api.v1.watch_service_pb2.WatchResponse, 31 | ] 32 | 33 | class WatchServiceServicer(metaclass=abc.ABCMeta): 34 | @abc.abstractmethod 35 | def Watch( 36 | self, 37 | request: authzed.api.v1.watch_service_pb2.WatchRequest, 38 | context: _ServicerContext, 39 | ) -> typing.Union[collections.abc.Iterator[authzed.api.v1.watch_service_pb2.WatchResponse], collections.abc.AsyncIterator[authzed.api.v1.watch_service_pb2.WatchResponse]]: ... 40 | 41 | def add_WatchServiceServicer_to_server(servicer: WatchServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 42 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/schema_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v1alpha1/schema.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v1alpha1/schema.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 26 | from validate import validate_pb2 as validate_dot_validate__pb2 27 | 28 | 29 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!authzed/api/v1alpha1/schema.proto\x12\x14\x61uthzed.api.v1alpha1\x1a\x1b\x62uf/validate/validate.proto\x1a\x17validate/validate.proto\"\xeb\x01\n\x11ReadSchemaRequest\x12\xd5\x01\n\x18object_definitions_names\x18\x01 \x03(\tB\x9a\x01\xfa\x42J\x92\x01G\"ErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaHJ\x92\x01G\"ErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$R\x16objectDefinitionsNames\"\x87\x01\n\x12ReadSchemaResponse\x12-\n\x12object_definitions\x18\x01 \x03(\tR\x11objectDefinitions\x12\x42\n\x1d\x63omputed_definitions_revision\x18\x02 \x01(\tR\x1b\x63omputedDefinitionsRevision\"\x9d\x01\n\x12WriteSchemaRequest\x12*\n\x06schema\x18\x01 \x01(\tB\x12\xfa\x42\x06r\x04(\x80\x80\x10\xbaH\x06r\x04(\x80\x80\x10R\x06schema\x12[\n*optional_definitions_revision_precondition\x18\x02 \x01(\tR\'optionalDefinitionsRevisionPrecondition\"\x93\x01\n\x13WriteSchemaResponse\x12\x38\n\x18object_definitions_names\x18\x01 \x03(\tR\x16objectDefinitionsNames\x12\x42\n\x1d\x63omputed_definitions_revision\x18\x02 \x01(\tR\x1b\x63omputedDefinitionsRevision2\xd8\x01\n\rSchemaService\x12\x61\n\nReadSchema\x12\'.authzed.api.v1alpha1.ReadSchemaRequest\x1a(.authzed.api.v1alpha1.ReadSchemaResponse\"\x00\x12\x64\n\x0bWriteSchema\x12(.authzed.api.v1alpha1.WriteSchemaRequest\x1a).authzed.api.v1alpha1.WriteSchemaResponse\"\x00\x42T\n\x18\x63om.authzed.api.v1alpha1Z8github.com/authzed/authzed-go/proto/authzed/api/v1alpha1b\x06proto3') 30 | 31 | _globals = globals() 32 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 33 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v1alpha1.schema_pb2', _globals) 34 | if not _descriptor._USE_C_DESCRIPTORS: 35 | _globals['DESCRIPTOR']._loaded_options = None 36 | _globals['DESCRIPTOR']._serialized_options = b'\n\030com.authzed.api.v1alpha1Z8github.com/authzed/authzed-go/proto/authzed/api/v1alpha1' 37 | _globals['_READSCHEMAREQUEST'].fields_by_name['object_definitions_names']._loaded_options = None 38 | _globals['_READSCHEMAREQUEST'].fields_by_name['object_definitions_names']._serialized_options = b'\372BJ\222\001G\"ErC(\200\0012>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\272HJ\222\001G\"ErC(\200\0012>^([a-z][a-z0-9_]{1,62}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$' 39 | _globals['_WRITESCHEMAREQUEST'].fields_by_name['schema']._loaded_options = None 40 | _globals['_WRITESCHEMAREQUEST'].fields_by_name['schema']._serialized_options = b'\372B\006r\004(\200\200\020\272H\006r\004(\200\200\020' 41 | _globals['_READSCHEMAREQUEST']._serialized_start=114 42 | _globals['_READSCHEMAREQUEST']._serialized_end=349 43 | _globals['_READSCHEMARESPONSE']._serialized_start=352 44 | _globals['_READSCHEMARESPONSE']._serialized_end=487 45 | _globals['_WRITESCHEMAREQUEST']._serialized_start=490 46 | _globals['_WRITESCHEMAREQUEST']._serialized_end=647 47 | _globals['_WRITESCHEMARESPONSE']._serialized_start=650 48 | _globals['_WRITESCHEMARESPONSE']._serialized_end=797 49 | _globals['_SCHEMASERVICE']._serialized_start=800 50 | _globals['_SCHEMASERVICE']._serialized_end=1016 51 | # @@protoc_insertion_point(module_scope) 52 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/schema_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import builtins 7 | import collections.abc 8 | import google.protobuf.descriptor 9 | import google.protobuf.internal.containers 10 | import google.protobuf.message 11 | import typing 12 | 13 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 14 | 15 | @typing.final 16 | class ReadSchemaRequest(google.protobuf.message.Message): 17 | """ReadSchemaRequest is the required data to read Object Definitions from 18 | a Schema. 19 | """ 20 | 21 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 22 | 23 | OBJECT_DEFINITIONS_NAMES_FIELD_NUMBER: builtins.int 24 | @property 25 | def object_definitions_names(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 26 | """The list of names of the Object Definitions that are being requested. 27 | 28 | These names must be fully qualified with their namespace (e.g. 29 | myblog/post). 30 | """ 31 | 32 | def __init__( 33 | self, 34 | *, 35 | object_definitions_names: collections.abc.Iterable[builtins.str] | None = ..., 36 | ) -> None: ... 37 | def ClearField(self, field_name: typing.Literal["object_definitions_names", b"object_definitions_names"]) -> None: ... 38 | 39 | global___ReadSchemaRequest = ReadSchemaRequest 40 | 41 | @typing.final 42 | class ReadSchemaResponse(google.protobuf.message.Message): 43 | """ReadSchemaResponse is the resulting data after having read the Object 44 | Definitions from a Schema. 45 | """ 46 | 47 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 48 | 49 | OBJECT_DEFINITIONS_FIELD_NUMBER: builtins.int 50 | COMPUTED_DEFINITIONS_REVISION_FIELD_NUMBER: builtins.int 51 | computed_definitions_revision: builtins.str 52 | """The computed revision of the returned object definitions.""" 53 | @property 54 | def object_definitions(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 55 | """The Object Definitions that were requested.""" 56 | 57 | def __init__( 58 | self, 59 | *, 60 | object_definitions: collections.abc.Iterable[builtins.str] | None = ..., 61 | computed_definitions_revision: builtins.str = ..., 62 | ) -> None: ... 63 | def ClearField(self, field_name: typing.Literal["computed_definitions_revision", b"computed_definitions_revision", "object_definitions", b"object_definitions"]) -> None: ... 64 | 65 | global___ReadSchemaResponse = ReadSchemaResponse 66 | 67 | @typing.final 68 | class WriteSchemaRequest(google.protobuf.message.Message): 69 | """WriteSchemaRequest is the required data used to "upsert" the Schema of a 70 | Permissions System. 71 | """ 72 | 73 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 74 | 75 | SCHEMA_FIELD_NUMBER: builtins.int 76 | OPTIONAL_DEFINITIONS_REVISION_PRECONDITION_FIELD_NUMBER: builtins.int 77 | schema: builtins.str 78 | """The Schema containing one or more Object Definitions that will be written 79 | to the Permissions System. 80 | 256KiB 81 | """ 82 | optional_definitions_revision_precondition: builtins.str 83 | """If specified, the existing revision of object definitions in the schema that must be present for 84 | the write to succeed. If the revision specified differs (i.e. the underlying schema has changed), 85 | the write call will fail with a FAILED_PRECONDITION error. 86 | """ 87 | def __init__( 88 | self, 89 | *, 90 | schema: builtins.str = ..., 91 | optional_definitions_revision_precondition: builtins.str = ..., 92 | ) -> None: ... 93 | def ClearField(self, field_name: typing.Literal["optional_definitions_revision_precondition", b"optional_definitions_revision_precondition", "schema", b"schema"]) -> None: ... 94 | 95 | global___WriteSchemaRequest = WriteSchemaRequest 96 | 97 | @typing.final 98 | class WriteSchemaResponse(google.protobuf.message.Message): 99 | """WriteSchemaResponse is the resulting data after having written a Schema to 100 | a Permissions System. 101 | """ 102 | 103 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 104 | 105 | OBJECT_DEFINITIONS_NAMES_FIELD_NUMBER: builtins.int 106 | COMPUTED_DEFINITIONS_REVISION_FIELD_NUMBER: builtins.int 107 | computed_definitions_revision: builtins.str 108 | """The computed revision of the written object definitions.""" 109 | @property 110 | def object_definitions_names(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: 111 | """The names of the Object Definitions that were written.""" 112 | 113 | def __init__( 114 | self, 115 | *, 116 | object_definitions_names: collections.abc.Iterable[builtins.str] | None = ..., 117 | computed_definitions_revision: builtins.str = ..., 118 | ) -> None: ... 119 | def ClearField(self, field_name: typing.Literal["computed_definitions_revision", b"computed_definitions_revision", "object_definitions_names", b"object_definitions_names"]) -> None: ... 120 | 121 | global___WriteSchemaResponse = WriteSchemaResponse 122 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/schema_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | from authzed.api.v1alpha1 import schema_pb2 as authzed_dot_api_dot_v1alpha1_dot_schema__pb2 6 | 7 | 8 | class SchemaServiceStub(object): 9 | """SchemaService implements operations on a Permissions System's Schema. 10 | """ 11 | 12 | def __init__(self, channel): 13 | """Constructor. 14 | 15 | Args: 16 | channel: A grpc.Channel. 17 | """ 18 | self.ReadSchema = channel.unary_unary( 19 | '/authzed.api.v1alpha1.SchemaService/ReadSchema', 20 | request_serializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaRequest.SerializeToString, 21 | response_deserializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaResponse.FromString, 22 | _registered_method=True) 23 | self.WriteSchema = channel.unary_unary( 24 | '/authzed.api.v1alpha1.SchemaService/WriteSchema', 25 | request_serializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaRequest.SerializeToString, 26 | response_deserializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaResponse.FromString, 27 | _registered_method=True) 28 | 29 | 30 | class SchemaServiceServicer(object): 31 | """SchemaService implements operations on a Permissions System's Schema. 32 | """ 33 | 34 | def ReadSchema(self, request, context): 35 | """Read returns the current Object Definitions for a Permissions System. 36 | 37 | Errors include: 38 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 39 | - NOT_FOUND: one of the Object Definitions being requested does not exist 40 | """ 41 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 42 | context.set_details('Method not implemented!') 43 | raise NotImplementedError('Method not implemented!') 44 | 45 | def WriteSchema(self, request, context): 46 | """Write overwrites the current Object Definitions for a Permissions System. 47 | 48 | Any Object Definitions that exist, but are not included will be deleted. 49 | """ 50 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 51 | context.set_details('Method not implemented!') 52 | raise NotImplementedError('Method not implemented!') 53 | 54 | 55 | def add_SchemaServiceServicer_to_server(servicer, server): 56 | rpc_method_handlers = { 57 | 'ReadSchema': grpc.unary_unary_rpc_method_handler( 58 | servicer.ReadSchema, 59 | request_deserializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaRequest.FromString, 60 | response_serializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaResponse.SerializeToString, 61 | ), 62 | 'WriteSchema': grpc.unary_unary_rpc_method_handler( 63 | servicer.WriteSchema, 64 | request_deserializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaRequest.FromString, 65 | response_serializer=authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaResponse.SerializeToString, 66 | ), 67 | } 68 | generic_handler = grpc.method_handlers_generic_handler( 69 | 'authzed.api.v1alpha1.SchemaService', rpc_method_handlers) 70 | server.add_generic_rpc_handlers((generic_handler,)) 71 | server.add_registered_method_handlers('authzed.api.v1alpha1.SchemaService', rpc_method_handlers) 72 | 73 | 74 | # This class is part of an EXPERIMENTAL API. 75 | class SchemaService(object): 76 | """SchemaService implements operations on a Permissions System's Schema. 77 | """ 78 | 79 | @staticmethod 80 | def ReadSchema(request, 81 | target, 82 | options=(), 83 | channel_credentials=None, 84 | call_credentials=None, 85 | insecure=False, 86 | compression=None, 87 | wait_for_ready=None, 88 | timeout=None, 89 | metadata=None): 90 | return grpc.experimental.unary_unary( 91 | request, 92 | target, 93 | '/authzed.api.v1alpha1.SchemaService/ReadSchema', 94 | authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaRequest.SerializeToString, 95 | authzed_dot_api_dot_v1alpha1_dot_schema__pb2.ReadSchemaResponse.FromString, 96 | options, 97 | channel_credentials, 98 | insecure, 99 | call_credentials, 100 | compression, 101 | wait_for_ready, 102 | timeout, 103 | metadata, 104 | _registered_method=True) 105 | 106 | @staticmethod 107 | def WriteSchema(request, 108 | target, 109 | options=(), 110 | channel_credentials=None, 111 | call_credentials=None, 112 | insecure=False, 113 | compression=None, 114 | wait_for_ready=None, 115 | timeout=None, 116 | metadata=None): 117 | return grpc.experimental.unary_unary( 118 | request, 119 | target, 120 | '/authzed.api.v1alpha1.SchemaService/WriteSchema', 121 | authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaRequest.SerializeToString, 122 | authzed_dot_api_dot_v1alpha1_dot_schema__pb2.WriteSchemaResponse.FromString, 123 | options, 124 | channel_credentials, 125 | insecure, 126 | call_credentials, 127 | compression, 128 | wait_for_ready, 129 | timeout, 130 | metadata, 131 | _registered_method=True) 132 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/schema_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.v1alpha1.schema_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class SchemaServiceStub: 21 | """SchemaService implements operations on a Permissions System's Schema.""" 22 | 23 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 24 | ReadSchema: grpc.UnaryUnaryMultiCallable[ 25 | authzed.api.v1alpha1.schema_pb2.ReadSchemaRequest, 26 | authzed.api.v1alpha1.schema_pb2.ReadSchemaResponse, 27 | ] 28 | """Read returns the current Object Definitions for a Permissions System. 29 | 30 | Errors include: 31 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 32 | - NOT_FOUND: one of the Object Definitions being requested does not exist 33 | """ 34 | 35 | WriteSchema: grpc.UnaryUnaryMultiCallable[ 36 | authzed.api.v1alpha1.schema_pb2.WriteSchemaRequest, 37 | authzed.api.v1alpha1.schema_pb2.WriteSchemaResponse, 38 | ] 39 | """Write overwrites the current Object Definitions for a Permissions System. 40 | 41 | Any Object Definitions that exist, but are not included will be deleted. 42 | """ 43 | 44 | class SchemaServiceAsyncStub: 45 | """SchemaService implements operations on a Permissions System's Schema.""" 46 | 47 | ReadSchema: grpc.aio.UnaryUnaryMultiCallable[ 48 | authzed.api.v1alpha1.schema_pb2.ReadSchemaRequest, 49 | authzed.api.v1alpha1.schema_pb2.ReadSchemaResponse, 50 | ] 51 | """Read returns the current Object Definitions for a Permissions System. 52 | 53 | Errors include: 54 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 55 | - NOT_FOUND: one of the Object Definitions being requested does not exist 56 | """ 57 | 58 | WriteSchema: grpc.aio.UnaryUnaryMultiCallable[ 59 | authzed.api.v1alpha1.schema_pb2.WriteSchemaRequest, 60 | authzed.api.v1alpha1.schema_pb2.WriteSchemaResponse, 61 | ] 62 | """Write overwrites the current Object Definitions for a Permissions System. 63 | 64 | Any Object Definitions that exist, but are not included will be deleted. 65 | """ 66 | 67 | class SchemaServiceServicer(metaclass=abc.ABCMeta): 68 | """SchemaService implements operations on a Permissions System's Schema.""" 69 | 70 | @abc.abstractmethod 71 | def ReadSchema( 72 | self, 73 | request: authzed.api.v1alpha1.schema_pb2.ReadSchemaRequest, 74 | context: _ServicerContext, 75 | ) -> typing.Union[authzed.api.v1alpha1.schema_pb2.ReadSchemaResponse, collections.abc.Awaitable[authzed.api.v1alpha1.schema_pb2.ReadSchemaResponse]]: 76 | """Read returns the current Object Definitions for a Permissions System. 77 | 78 | Errors include: 79 | - INVALID_ARGUMENT: a provided value has failed to semantically validate 80 | - NOT_FOUND: one of the Object Definitions being requested does not exist 81 | """ 82 | 83 | @abc.abstractmethod 84 | def WriteSchema( 85 | self, 86 | request: authzed.api.v1alpha1.schema_pb2.WriteSchemaRequest, 87 | context: _ServicerContext, 88 | ) -> typing.Union[authzed.api.v1alpha1.schema_pb2.WriteSchemaResponse, collections.abc.Awaitable[authzed.api.v1alpha1.schema_pb2.WriteSchemaResponse]]: 89 | """Write overwrites the current Object Definitions for a Permissions System. 90 | 91 | Any Object Definitions that exist, but are not included will be deleted. 92 | """ 93 | 94 | def add_SchemaServiceServicer_to_server(servicer: SchemaServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 95 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/watchresources_service_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: authzed/api/v1alpha1/watchresources_service.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'authzed/api/v1alpha1/watchresources_service.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from authzed.api.v1 import core_pb2 as authzed_dot_api_dot_v1_dot_core__pb2 26 | from buf.validate import validate_pb2 as buf_dot_validate_dot_validate__pb2 27 | from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 28 | from validate import validate_pb2 as validate_dot_validate__pb2 29 | 30 | 31 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n1authzed/api/v1alpha1/watchresources_service.proto\x12\x14\x61uthzed.api.v1alpha1\x1a\x19\x61uthzed/api/v1/core.proto\x1a\x1b\x62uf/validate/validate.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x17validate/validate.proto\"\x87\x04\n\x15WatchResourcesRequest\x12\xc3\x01\n\x14resource_object_type\x18\x01 \x01(\tB\x90\x01\xfa\x42\x45rC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaHErC(\x80\x01\x32>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$R\x12resourceObjectType\x12n\n\npermission\x18\x02 \x01(\tBN\xfa\x42$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$\xbaH$r\"(@2\x1e^[a-z][a-z0-9_]{1,62}[a-z0-9]$R\npermission\x12.\n\x13subject_object_type\x18\x03 \x01(\tR\x11subjectObjectType\x12:\n\x19optional_subject_relation\x18\x04 \x01(\tR\x17optionalSubjectRelation\x12L\n\x15optional_start_cursor\x18\x05 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x13optionalStartCursor\"\x84\x03\n\x10PermissionUpdate\x12:\n\x07subject\x18\x01 \x01(\x0b\x32 .authzed.api.v1.SubjectReferenceR\x07subject\x12;\n\x08resource\x18\x02 \x01(\x0b\x32\x1f.authzed.api.v1.ObjectReferenceR\x08resource\x12\x1a\n\x08relation\x18\x03 \x01(\tR\x08relation\x12\x64\n\x12updated_permission\x18\x04 \x01(\x0e\x32\x35.authzed.api.v1alpha1.PermissionUpdate.PermissionshipR\x11updatedPermission\"u\n\x0ePermissionship\x12\x1e\n\x1aPERMISSIONSHIP_UNSPECIFIED\x10\x00\x12 \n\x1cPERMISSIONSHIP_NO_PERMISSION\x10\x01\x12!\n\x1dPERMISSIONSHIP_HAS_PERMISSION\x10\x02\"\x9d\x01\n\x16WatchResourcesResponse\x12@\n\x07updates\x18\x01 \x03(\x0b\x32&.authzed.api.v1alpha1.PermissionUpdateR\x07updates\x12\x41\n\x0f\x63hanges_through\x18\x02 \x01(\x0b\x32\x18.authzed.api.v1.ZedTokenR\x0e\x63hangesThrough2\xa9\x01\n\x15WatchResourcesService\x12\x8f\x01\n\x0eWatchResources\x12+.authzed.api.v1alpha1.WatchResourcesRequest\x1a,.authzed.api.v1alpha1.WatchResourcesResponse\" \x82\xd3\xe4\x93\x02\x1a\"\x15/v1alpha1/lookupwatch:\x01*0\x01\x42T\n\x18\x63om.authzed.api.v1alpha1Z8github.com/authzed/authzed-go/proto/authzed/api/v1alpha1b\x06proto3') 32 | 33 | _globals = globals() 34 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 35 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'authzed.api.v1alpha1.watchresources_service_pb2', _globals) 36 | if not _descriptor._USE_C_DESCRIPTORS: 37 | _globals['DESCRIPTOR']._loaded_options = None 38 | _globals['DESCRIPTOR']._serialized_options = b'\n\030com.authzed.api.v1alpha1Z8github.com/authzed/authzed-go/proto/authzed/api/v1alpha1' 39 | _globals['_WATCHRESOURCESREQUEST'].fields_by_name['resource_object_type']._loaded_options = None 40 | _globals['_WATCHRESOURCESREQUEST'].fields_by_name['resource_object_type']._serialized_options = b'\372BErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$\272HErC(\200\0012>^([a-z][a-z0-9_]{1,61}[a-z0-9]/)*[a-z][a-z0-9_]{1,62}[a-z0-9]$' 41 | _globals['_WATCHRESOURCESREQUEST'].fields_by_name['permission']._loaded_options = None 42 | _globals['_WATCHRESOURCESREQUEST'].fields_by_name['permission']._serialized_options = b'\372B$r\"(@2\036^[a-z][a-z0-9_]{1,62}[a-z0-9]$\272H$r\"(@2\036^[a-z][a-z0-9_]{1,62}[a-z0-9]$' 43 | _globals['_WATCHRESOURCESSERVICE'].methods_by_name['WatchResources']._loaded_options = None 44 | _globals['_WATCHRESOURCESSERVICE'].methods_by_name['WatchResources']._serialized_options = b'\202\323\344\223\002\032\"\025/v1alpha1/lookupwatch:\001*' 45 | _globals['_WATCHRESOURCESREQUEST']._serialized_start=187 46 | _globals['_WATCHRESOURCESREQUEST']._serialized_end=706 47 | _globals['_PERMISSIONUPDATE']._serialized_start=709 48 | _globals['_PERMISSIONUPDATE']._serialized_end=1097 49 | _globals['_PERMISSIONUPDATE_PERMISSIONSHIP']._serialized_start=980 50 | _globals['_PERMISSIONUPDATE_PERMISSIONSHIP']._serialized_end=1097 51 | _globals['_WATCHRESOURCESRESPONSE']._serialized_start=1100 52 | _globals['_WATCHRESOURCESRESPONSE']._serialized_end=1257 53 | _globals['_WATCHRESOURCESSERVICE']._serialized_start=1260 54 | _globals['_WATCHRESOURCESSERVICE']._serialized_end=1429 55 | # @@protoc_insertion_point(module_scope) 56 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/watchresources_service_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import authzed.api.v1.core_pb2 7 | import builtins 8 | import collections.abc 9 | import google.protobuf.descriptor 10 | import google.protobuf.internal.containers 11 | import google.protobuf.internal.enum_type_wrapper 12 | import google.protobuf.message 13 | import sys 14 | import typing 15 | 16 | if sys.version_info >= (3, 10): 17 | import typing as typing_extensions 18 | else: 19 | import typing_extensions 20 | 21 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 22 | 23 | @typing.final 24 | class WatchResourcesRequest(google.protobuf.message.Message): 25 | """WatchResourcesRequest starts a watch for specific permission updates 26 | for the given resource and subject types. 27 | """ 28 | 29 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 30 | 31 | RESOURCE_OBJECT_TYPE_FIELD_NUMBER: builtins.int 32 | PERMISSION_FIELD_NUMBER: builtins.int 33 | SUBJECT_OBJECT_TYPE_FIELD_NUMBER: builtins.int 34 | OPTIONAL_SUBJECT_RELATION_FIELD_NUMBER: builtins.int 35 | OPTIONAL_START_CURSOR_FIELD_NUMBER: builtins.int 36 | resource_object_type: builtins.str 37 | """resource_object_type is the type of resource object for which we will 38 | watch for changes. 39 | """ 40 | permission: builtins.str 41 | """permission is the name of the permission or relation for which we will 42 | watch for changes. 43 | """ 44 | subject_object_type: builtins.str 45 | """subject_object_type is the type of the subject resource for which we will 46 | watch for changes. 47 | """ 48 | optional_subject_relation: builtins.str 49 | """optional_subject_relation allows you to specify a group of subjects to watch 50 | for a given subject type. 51 | """ 52 | @property 53 | def optional_start_cursor(self) -> authzed.api.v1.core_pb2.ZedToken: ... 54 | def __init__( 55 | self, 56 | *, 57 | resource_object_type: builtins.str = ..., 58 | permission: builtins.str = ..., 59 | subject_object_type: builtins.str = ..., 60 | optional_subject_relation: builtins.str = ..., 61 | optional_start_cursor: authzed.api.v1.core_pb2.ZedToken | None = ..., 62 | ) -> None: ... 63 | def HasField(self, field_name: typing.Literal["optional_start_cursor", b"optional_start_cursor"]) -> builtins.bool: ... 64 | def ClearField(self, field_name: typing.Literal["optional_start_cursor", b"optional_start_cursor", "optional_subject_relation", b"optional_subject_relation", "permission", b"permission", "resource_object_type", b"resource_object_type", "subject_object_type", b"subject_object_type"]) -> None: ... 65 | 66 | global___WatchResourcesRequest = WatchResourcesRequest 67 | 68 | @typing.final 69 | class PermissionUpdate(google.protobuf.message.Message): 70 | """PermissionUpdate represents a single permission update for a specific 71 | subject's permissions. 72 | """ 73 | 74 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 75 | 76 | class _Permissionship: 77 | ValueType = typing.NewType("ValueType", builtins.int) 78 | V: typing_extensions.TypeAlias = ValueType 79 | 80 | class _PermissionshipEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[PermissionUpdate._Permissionship.ValueType], builtins.type): 81 | DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor 82 | PERMISSIONSHIP_UNSPECIFIED: PermissionUpdate._Permissionship.ValueType # 0 83 | PERMISSIONSHIP_NO_PERMISSION: PermissionUpdate._Permissionship.ValueType # 1 84 | PERMISSIONSHIP_HAS_PERMISSION: PermissionUpdate._Permissionship.ValueType # 2 85 | 86 | class Permissionship(_Permissionship, metaclass=_PermissionshipEnumTypeWrapper): 87 | """todo: work this into the v1 core API at some point since it's used 88 | across services. 89 | """ 90 | 91 | PERMISSIONSHIP_UNSPECIFIED: PermissionUpdate.Permissionship.ValueType # 0 92 | PERMISSIONSHIP_NO_PERMISSION: PermissionUpdate.Permissionship.ValueType # 1 93 | PERMISSIONSHIP_HAS_PERMISSION: PermissionUpdate.Permissionship.ValueType # 2 94 | 95 | SUBJECT_FIELD_NUMBER: builtins.int 96 | RESOURCE_FIELD_NUMBER: builtins.int 97 | RELATION_FIELD_NUMBER: builtins.int 98 | UPDATED_PERMISSION_FIELD_NUMBER: builtins.int 99 | relation: builtins.str 100 | updated_permission: global___PermissionUpdate.Permissionship.ValueType 101 | @property 102 | def subject(self) -> authzed.api.v1.core_pb2.SubjectReference: 103 | """subject defines the subject resource whose permissions have changed.""" 104 | 105 | @property 106 | def resource(self) -> authzed.api.v1.core_pb2.ObjectReference: 107 | """resource defines the specific object in the system.""" 108 | 109 | def __init__( 110 | self, 111 | *, 112 | subject: authzed.api.v1.core_pb2.SubjectReference | None = ..., 113 | resource: authzed.api.v1.core_pb2.ObjectReference | None = ..., 114 | relation: builtins.str = ..., 115 | updated_permission: global___PermissionUpdate.Permissionship.ValueType = ..., 116 | ) -> None: ... 117 | def HasField(self, field_name: typing.Literal["resource", b"resource", "subject", b"subject"]) -> builtins.bool: ... 118 | def ClearField(self, field_name: typing.Literal["relation", b"relation", "resource", b"resource", "subject", b"subject", "updated_permission", b"updated_permission"]) -> None: ... 119 | 120 | global___PermissionUpdate = PermissionUpdate 121 | 122 | @typing.final 123 | class WatchResourcesResponse(google.protobuf.message.Message): 124 | """WatchResourcesResponse enumerates the list of permission updates that have 125 | occurred as a result of one or more relationship updates. 126 | """ 127 | 128 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 129 | 130 | UPDATES_FIELD_NUMBER: builtins.int 131 | CHANGES_THROUGH_FIELD_NUMBER: builtins.int 132 | @property 133 | def updates(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___PermissionUpdate]: ... 134 | @property 135 | def changes_through(self) -> authzed.api.v1.core_pb2.ZedToken: ... 136 | def __init__( 137 | self, 138 | *, 139 | updates: collections.abc.Iterable[global___PermissionUpdate] | None = ..., 140 | changes_through: authzed.api.v1.core_pb2.ZedToken | None = ..., 141 | ) -> None: ... 142 | def HasField(self, field_name: typing.Literal["changes_through", b"changes_through"]) -> builtins.bool: ... 143 | def ClearField(self, field_name: typing.Literal["changes_through", b"changes_through", "updates", b"updates"]) -> None: ... 144 | 145 | global___WatchResourcesResponse = WatchResourcesResponse 146 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/watchresources_service_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | from authzed.api.v1alpha1 import watchresources_service_pb2 as authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2 6 | 7 | 8 | class WatchResourcesServiceStub(object): 9 | """WatchResourcesService is used to receive a stream of updates for resources of a 10 | specific (resource type, permission, subject) combination. 11 | """ 12 | 13 | def __init__(self, channel): 14 | """Constructor. 15 | 16 | Args: 17 | channel: A grpc.Channel. 18 | """ 19 | self.WatchResources = channel.unary_stream( 20 | '/authzed.api.v1alpha1.WatchResourcesService/WatchResources', 21 | request_serializer=authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesRequest.SerializeToString, 22 | response_deserializer=authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesResponse.FromString, 23 | _registered_method=True) 24 | 25 | 26 | class WatchResourcesServiceServicer(object): 27 | """WatchResourcesService is used to receive a stream of updates for resources of a 28 | specific (resource type, permission, subject) combination. 29 | """ 30 | 31 | def WatchResources(self, request, context): 32 | """WatchResources initiates a watch for permission changes for the provided 33 | (resource type, permission, subject) pair. 34 | """ 35 | context.set_code(grpc.StatusCode.UNIMPLEMENTED) 36 | context.set_details('Method not implemented!') 37 | raise NotImplementedError('Method not implemented!') 38 | 39 | 40 | def add_WatchResourcesServiceServicer_to_server(servicer, server): 41 | rpc_method_handlers = { 42 | 'WatchResources': grpc.unary_stream_rpc_method_handler( 43 | servicer.WatchResources, 44 | request_deserializer=authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesRequest.FromString, 45 | response_serializer=authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesResponse.SerializeToString, 46 | ), 47 | } 48 | generic_handler = grpc.method_handlers_generic_handler( 49 | 'authzed.api.v1alpha1.WatchResourcesService', rpc_method_handlers) 50 | server.add_generic_rpc_handlers((generic_handler,)) 51 | server.add_registered_method_handlers('authzed.api.v1alpha1.WatchResourcesService', rpc_method_handlers) 52 | 53 | 54 | # This class is part of an EXPERIMENTAL API. 55 | class WatchResourcesService(object): 56 | """WatchResourcesService is used to receive a stream of updates for resources of a 57 | specific (resource type, permission, subject) combination. 58 | """ 59 | 60 | @staticmethod 61 | def WatchResources(request, 62 | target, 63 | options=(), 64 | channel_credentials=None, 65 | call_credentials=None, 66 | insecure=False, 67 | compression=None, 68 | wait_for_ready=None, 69 | timeout=None, 70 | metadata=None): 71 | return grpc.experimental.unary_stream( 72 | request, 73 | target, 74 | '/authzed.api.v1alpha1.WatchResourcesService/WatchResources', 75 | authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesRequest.SerializeToString, 76 | authzed_dot_api_dot_v1alpha1_dot_watchresources__service__pb2.WatchResourcesResponse.FromString, 77 | options, 78 | channel_credentials, 79 | insecure, 80 | call_credentials, 81 | compression, 82 | wait_for_ready, 83 | timeout, 84 | metadata, 85 | _registered_method=True) 86 | -------------------------------------------------------------------------------- /authzed/api/v1alpha1/watchresources_service_pb2_grpc.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import abc 7 | import authzed.api.v1alpha1.watchresources_service_pb2 8 | import collections.abc 9 | import grpc 10 | import grpc.aio 11 | import typing 12 | 13 | _T = typing.TypeVar("_T") 14 | 15 | class _MaybeAsyncIterator(collections.abc.AsyncIterator[_T], collections.abc.Iterator[_T], metaclass=abc.ABCMeta): ... 16 | 17 | class _ServicerContext(grpc.ServicerContext, grpc.aio.ServicerContext): # type: ignore[misc, type-arg] 18 | ... 19 | 20 | class WatchResourcesServiceStub: 21 | """WatchResourcesService is used to receive a stream of updates for resources of a 22 | specific (resource type, permission, subject) combination. 23 | """ 24 | 25 | def __init__(self, channel: typing.Union[grpc.Channel, grpc.aio.Channel]) -> None: ... 26 | WatchResources: grpc.UnaryStreamMultiCallable[ 27 | authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesRequest, 28 | authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesResponse, 29 | ] 30 | """WatchResources initiates a watch for permission changes for the provided 31 | (resource type, permission, subject) pair. 32 | """ 33 | 34 | class WatchResourcesServiceAsyncStub: 35 | """WatchResourcesService is used to receive a stream of updates for resources of a 36 | specific (resource type, permission, subject) combination. 37 | """ 38 | 39 | WatchResources: grpc.aio.UnaryStreamMultiCallable[ 40 | authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesRequest, 41 | authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesResponse, 42 | ] 43 | """WatchResources initiates a watch for permission changes for the provided 44 | (resource type, permission, subject) pair. 45 | """ 46 | 47 | class WatchResourcesServiceServicer(metaclass=abc.ABCMeta): 48 | """WatchResourcesService is used to receive a stream of updates for resources of a 49 | specific (resource type, permission, subject) combination. 50 | """ 51 | 52 | @abc.abstractmethod 53 | def WatchResources( 54 | self, 55 | request: authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesRequest, 56 | context: _ServicerContext, 57 | ) -> typing.Union[collections.abc.Iterator[authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesResponse], collections.abc.AsyncIterator[authzed.api.v1alpha1.watchresources_service_pb2.WatchResourcesResponse]]: 58 | """WatchResources initiates a watch for permission changes for the provided 59 | (resource type, permission, subject) pair. 60 | """ 61 | 62 | def add_WatchResourcesServiceServicer_to_server(servicer: WatchResourcesServiceServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ... 63 | -------------------------------------------------------------------------------- /authzed/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/authzed/authzed-py/c99293eb1c74b22748e572c46f587e746cd290a4/authzed/py.typed -------------------------------------------------------------------------------- /buf.gen.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | version: "v2" 3 | plugins: 4 | - remote: "buf.build/protocolbuffers/python:v28.3" 5 | include_imports: true 6 | out: "." 7 | - remote: "buf.build/grpc/python:v1.67.1" 8 | out: "." 9 | - remote: "buf.build/community/nipunn1313-mypy:v3.6.0" 10 | include_imports: true 11 | out: "." 12 | inputs: 13 | # NOTE: this references a variant of 1.41.0 that includes the protovalidate code. 14 | - module: "buf.build/authzed/api:use-protovalidate-instead-of-protoc-gen-validate" 15 | -------------------------------------------------------------------------------- /examples/v1/bulk_check_permissions.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import ( 2 | BulkCheckPermissionRequest, 3 | BulkCheckPermissionRequestItem, 4 | CheckPermissionResponse, 5 | Client, 6 | Consistency, 7 | ObjectReference, 8 | SubjectReference, 9 | ) 10 | from grpcutil import bearer_token_credentials 11 | 12 | emilia = SubjectReference( 13 | object=ObjectReference( 14 | object_type="blog/user", 15 | object_id="emilia", 16 | ) 17 | ) 18 | beatrice = SubjectReference( 19 | object=ObjectReference( 20 | object_type="blog/user", 21 | object_id="beatrice", 22 | ) 23 | ) 24 | 25 | post_one = ObjectReference(object_type="blog/post", object_id="1") 26 | 27 | client = Client( 28 | "grpc.authzed.com:443", 29 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 30 | ) 31 | 32 | resp = client.BulkCheckPermission( 33 | BulkCheckPermissionRequest( 34 | consistency=Consistency(fully_consistent=True), 35 | items=[ 36 | BulkCheckPermissionRequestItem( 37 | resource=post_one, 38 | permission="view", 39 | subject=beatrice, 40 | ), 41 | BulkCheckPermissionRequestItem( 42 | resource=post_one, 43 | permission="write", 44 | subject=beatrice, 45 | ), 46 | ], 47 | ) 48 | ) 49 | assert len(resp.pairs) == 2 50 | assert resp.pairs[0].item.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 51 | assert resp.pairs[1].item.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 52 | -------------------------------------------------------------------------------- /examples/v1/bulk_import_export_relationships.py: -------------------------------------------------------------------------------- 1 | """ 2 | This demonstrates the simplest possible usage of the bulk 3 | import and export functionality. See import_bulk_relationships.py 4 | for a more realistic example of batching. 5 | """ 6 | 7 | from authzed.api.v1 import ( 8 | BulkExportRelationshipsRequest, 9 | BulkImportRelationshipsRequest, 10 | Client, 11 | Consistency, 12 | ObjectReference, 13 | Relationship, 14 | SubjectReference, 15 | WriteSchemaRequest, 16 | ) 17 | from grpcutil import insecure_bearer_token_credentials 18 | 19 | emilia = SubjectReference( 20 | object=ObjectReference( 21 | object_type="user", 22 | object_id="emilia", 23 | ) 24 | ) 25 | beatrice = SubjectReference( 26 | object=ObjectReference( 27 | object_type="user", 28 | object_id="beatrice", 29 | ) 30 | ) 31 | 32 | post_one = ObjectReference(object_type="post", object_id="1") 33 | 34 | client = Client( 35 | "localhost:50051", 36 | insecure_bearer_token_credentials("t_your_token_here_1234567deadbeef"), 37 | ) 38 | 39 | schema = """ 40 | definition post { 41 | relation writer: user 42 | relation reader: user 43 | 44 | permission write = writer 45 | permission view = reader + writer 46 | } 47 | definition user {} 48 | """ 49 | client.WriteSchema(WriteSchemaRequest(schema=schema)) 50 | 51 | 52 | reqs = [ 53 | BulkImportRelationshipsRequest( 54 | relationships=[ 55 | Relationship( 56 | resource=post_one, 57 | relation="reader", 58 | subject=emilia, 59 | ), 60 | Relationship( 61 | resource=post_one, 62 | relation="writer", 63 | subject=beatrice, 64 | ), 65 | ] 66 | ) 67 | ] 68 | 69 | import_reps = client.BulkImportRelationships((req for req in reqs)) 70 | assert import_reps.num_loaded == 2 71 | 72 | export_resp = client.BulkExportRelationships( 73 | BulkExportRelationshipsRequest(consistency=Consistency(fully_consistent=True)) 74 | ) 75 | 76 | rels = [] 77 | for response in export_resp: 78 | for rel in response.relationships: 79 | rels.append(rel) 80 | assert len(rels) == 2 81 | -------------------------------------------------------------------------------- /examples/v1/check_permissions.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import ( 2 | CheckPermissionRequest, 3 | CheckPermissionResponse, 4 | Client, 5 | ObjectReference, 6 | SubjectReference, 7 | ) 8 | from grpcutil import bearer_token_credentials 9 | 10 | emilia = SubjectReference( 11 | object=ObjectReference( 12 | object_type="blog/user", 13 | object_id="emilia", 14 | ) 15 | ) 16 | beatrice = SubjectReference( 17 | object=ObjectReference( 18 | object_type="blog/user", 19 | object_id="beatrice", 20 | ) 21 | ) 22 | 23 | post_one = ObjectReference(object_type="blog/post", object_id="1") 24 | 25 | client = Client( 26 | "grpc.authzed.com:443", 27 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 28 | ) 29 | 30 | resp = client.CheckPermission( 31 | CheckPermissionRequest( 32 | resource=post_one, 33 | permission="reader", 34 | subject=emilia, 35 | ) 36 | ) 37 | assert resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 38 | 39 | resp = client.CheckPermission( 40 | CheckPermissionRequest( 41 | resource=post_one, 42 | permission="writer", 43 | subject=emilia, 44 | ) 45 | ) 46 | assert resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 47 | 48 | resp = client.CheckPermission( 49 | CheckPermissionRequest( 50 | resource=post_one, 51 | permission="reader", 52 | subject=beatrice, 53 | ) 54 | ) 55 | assert resp.permissionship == CheckPermissionResponse.PERMISSIONSHIP_HAS_PERMISSION 56 | 57 | resp = client.CheckPermission( 58 | CheckPermissionRequest( 59 | resource=post_one, 60 | permission="writer", 61 | subject=beatrice, 62 | ) 63 | ) 64 | -------------------------------------------------------------------------------- /examples/v1/import_bulk_relationships.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is intended to be a (slightly) more real-world example 3 | that demonstrates the two levels of batching in making BulkImportRelationships 4 | requests. 5 | 6 | This example makes use of itertools.batched to break up an iterator of relationships 7 | into chunks. Documentation for itertools.batched can be found here: 8 | https://docs.python.org/3/library/itertools.html#itertools.batched 9 | """ 10 | 11 | from itertools import batched 12 | 13 | from authzed.api.v1 import ( 14 | Client, 15 | ObjectReference, 16 | Relationship, 17 | SubjectReference, 18 | WriteSchemaRequest, 19 | ) 20 | from authzed.api.v1.permission_service_pb2 import ImportBulkRelationshipsRequest 21 | from grpcutil import insecure_bearer_token_credentials 22 | 23 | TOKEN = "sometoken" 24 | 25 | # Stand up a client 26 | client = Client( 27 | "localhost:50051", 28 | insecure_bearer_token_credentials(TOKEN), 29 | ) 30 | 31 | # Write a simple schema 32 | schema = """ 33 | definition user {} 34 | definition resource { 35 | relation viewer: user 36 | permission view = viewer 37 | } 38 | """ 39 | 40 | client.WriteSchema(WriteSchemaRequest(schema=schema)) 41 | 42 | 43 | # A generator that we can use to create an arbitrarily-long list of relationships 44 | # In your own application, this would be whatever's generating the list of imported 45 | # relationships. 46 | def relationship_generator(num_relationships): 47 | idx = 0 48 | while idx < num_relationships: 49 | idx += 1 50 | yield Relationship( 51 | resource=ObjectReference(object_type="resource", object_id=str(idx)), 52 | relation="viewer", 53 | subject=SubjectReference( 54 | object=ObjectReference(object_type="user", object_id="our_user") 55 | ), 56 | ) 57 | 58 | 59 | TOTAL_RELATIONSHIPS_TO_WRITE = 1_000 60 | 61 | RELATIONSHIPS_PER_TRANSACTION = 100 62 | RELATIONSHIPS_PER_REQUEST_CHUNK = 10 63 | 64 | # NOTE: batched takes a larger iterator and makes an iterator of smaller chunks out of it. 65 | # We iterate over chunks of size RELATIONSHIPS_PER_TRANSACTION, and then we break each request into 66 | # chunks of size RELATIONSHIPS_PER_REQUEST_CHUNK. 67 | transaction_chunks = batched( 68 | relationship_generator(TOTAL_RELATIONSHIPS_TO_WRITE), RELATIONSHIPS_PER_TRANSACTION 69 | ) 70 | for relationships_for_request in transaction_chunks: 71 | request_chunks = batched(relationships_for_request, RELATIONSHIPS_PER_REQUEST_CHUNK) 72 | response = client.ImportBulkRelationships( 73 | ( 74 | ImportBulkRelationshipsRequest(relationships=relationships_chunk) 75 | for relationships_chunk in request_chunks 76 | ) 77 | ) 78 | print("request successful") 79 | print(response.num_loaded) 80 | -------------------------------------------------------------------------------- /examples/v1/read_schema.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import Client, ReadSchemaRequest 2 | from grpcutil import bearer_token_credentials 3 | 4 | client = Client( 5 | "grpc.authzed.com:443", 6 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 7 | ) 8 | 9 | resp = client.ReadSchema(ReadSchemaRequest()) 10 | print(resp.schema_text) 11 | -------------------------------------------------------------------------------- /examples/v1/write_relationships.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import ( 2 | Client, 3 | ObjectReference, 4 | Relationship, 5 | RelationshipUpdate, 6 | SubjectReference, 7 | WriteRelationshipsRequest, 8 | ) 9 | from grpcutil import bearer_token_credentials 10 | 11 | client = Client( 12 | "grpc.authzed.com:443", 13 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 14 | ) 15 | 16 | resp = client.WriteRelationships( 17 | WriteRelationshipsRequest( 18 | updates=[ 19 | # Emilia is a Writer on Post 1 20 | RelationshipUpdate( 21 | operation=RelationshipUpdate.Operation.OPERATION_CREATE, 22 | relationship=Relationship( 23 | resource=ObjectReference(object_type="blog/post", object_id="1"), 24 | relation="writer", 25 | subject=SubjectReference( 26 | object=ObjectReference( 27 | object_type="blog/user", 28 | object_id="emilia", 29 | ) 30 | ), 31 | ), 32 | ), 33 | # Beatrice is a Reader on Post 1 34 | RelationshipUpdate( 35 | operation=RelationshipUpdate.Operation.OPERATION_CREATE, 36 | relationship=Relationship( 37 | resource=ObjectReference(object_type="blog/post", object_id="1"), 38 | relation="reader", 39 | subject=SubjectReference( 40 | object=ObjectReference( 41 | object_type="blog/user", 42 | object_id="beatrice", 43 | ) 44 | ), 45 | ), 46 | ), 47 | ] 48 | ) 49 | ) 50 | -------------------------------------------------------------------------------- /examples/v1/write_schemas.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import Client, WriteSchemaRequest 2 | from grpcutil import bearer_token_credentials 3 | 4 | SCHEMA = """definition blog/user {} 5 | 6 | definition blog/post { 7 | relation reader: blog/user 8 | relation writer: blog/user 9 | 10 | permission read = reader + writer 11 | permission write = writer 12 | }""" 13 | 14 | client = Client( 15 | "grpc.authzed.com:443", 16 | bearer_token_credentials("t_your_token_here_1234567deadbeef"), 17 | ) 18 | 19 | resp = client.WriteSchema(WriteSchemaRequest(schema=SCHEMA)) 20 | -------------------------------------------------------------------------------- /examples/v1alpha1/read_schema.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1alpha1 import Client, ReadSchemaRequest 2 | from grpcutil import bearer_token_credentials 3 | 4 | client = Client("grpc.authzed.com:443", bearer_token_credentials("mytoken")) 5 | resp = client.ReadSchema(ReadSchemaRequest(object_definitions_names=["example/user"])) 6 | print(resp.object_definitions) 7 | -------------------------------------------------------------------------------- /examples/v1alpha1/read_schema_async.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from authzed.api.v1alpha1 import Client, ReadSchemaRequest 4 | from grpcutil import bearer_token_credentials 5 | 6 | 7 | async def async_new_client(): 8 | # Within an async context, the client's methods are all async: 9 | client = Client("grpc.authzed.com:443", bearer_token_credentials("mytoken")) 10 | resp = await client.ReadSchema(ReadSchemaRequest(object_definitions_names=["example/user"])) 11 | print(resp) 12 | 13 | 14 | loop = asyncio.get_event_loop() 15 | try: 16 | loop.run_until_complete(async_new_client()) 17 | finally: 18 | loop.close() 19 | -------------------------------------------------------------------------------- /google/api/annotations_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: google/api/annotations.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'google/api/annotations.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from google.api import http_pb2 as google_dot_api_dot_http__pb2 26 | from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 27 | 28 | 29 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1cgoogle/api/annotations.proto\x12\ngoogle.api\x1a\x15google/api/http.proto\x1a google/protobuf/descriptor.proto:K\n\x04http\x12\x1e.google.protobuf.MethodOptions\x18\xb0\xca\xbc\" \x01(\x0b\x32\x14.google.api.HttpRuleR\x04httpBn\n\x0e\x63om.google.apiB\x10\x41nnotationsProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3') 30 | 31 | _globals = globals() 32 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 33 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.api.annotations_pb2', _globals) 34 | if not _descriptor._USE_C_DESCRIPTORS: 35 | _globals['DESCRIPTOR']._loaded_options = None 36 | _globals['DESCRIPTOR']._serialized_options = b'\n\016com.google.apiB\020AnnotationsProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI' 37 | # @@protoc_insertion_point(module_scope) 38 | -------------------------------------------------------------------------------- /google/api/annotations_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | Copyright 2025 Google LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | """ 18 | 19 | import builtins 20 | import google.api.http_pb2 21 | import google.protobuf.descriptor 22 | import google.protobuf.descriptor_pb2 23 | import google.protobuf.internal.extension_dict 24 | 25 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 26 | 27 | HTTP_FIELD_NUMBER: builtins.int 28 | http: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MethodOptions, google.api.http_pb2.HttpRule] 29 | """See `HttpRule`.""" 30 | -------------------------------------------------------------------------------- /google/api/http_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: google/api/http.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'google/api/http.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | 26 | 27 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x15google/api/http.proto\x12\ngoogle.api\"y\n\x04Http\x12*\n\x05rules\x18\x01 \x03(\x0b\x32\x14.google.api.HttpRuleR\x05rules\x12\x45\n\x1f\x66ully_decode_reserved_expansion\x18\x02 \x01(\x08R\x1c\x66ullyDecodeReservedExpansion\"\xda\x02\n\x08HttpRule\x12\x1a\n\x08selector\x18\x01 \x01(\tR\x08selector\x12\x12\n\x03get\x18\x02 \x01(\tH\x00R\x03get\x12\x12\n\x03put\x18\x03 \x01(\tH\x00R\x03put\x12\x14\n\x04post\x18\x04 \x01(\tH\x00R\x04post\x12\x18\n\x06\x64\x65lete\x18\x05 \x01(\tH\x00R\x06\x64\x65lete\x12\x16\n\x05patch\x18\x06 \x01(\tH\x00R\x05patch\x12\x37\n\x06\x63ustom\x18\x08 \x01(\x0b\x32\x1d.google.api.CustomHttpPatternH\x00R\x06\x63ustom\x12\x12\n\x04\x62ody\x18\x07 \x01(\tR\x04\x62ody\x12#\n\rresponse_body\x18\x0c \x01(\tR\x0cresponseBody\x12\x45\n\x13\x61\x64\x64itional_bindings\x18\x0b \x03(\x0b\x32\x14.google.api.HttpRuleR\x12\x61\x64\x64itionalBindingsB\t\n\x07pattern\";\n\x11\x43ustomHttpPattern\x12\x12\n\x04kind\x18\x01 \x01(\tR\x04kind\x12\x12\n\x04path\x18\x02 \x01(\tR\x04pathBg\n\x0e\x63om.google.apiB\tHttpProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3') 28 | 29 | _globals = globals() 30 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 31 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.api.http_pb2', _globals) 32 | if not _descriptor._USE_C_DESCRIPTORS: 33 | _globals['DESCRIPTOR']._loaded_options = None 34 | _globals['DESCRIPTOR']._serialized_options = b'\n\016com.google.apiB\tHttpProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI' 35 | _globals['_HTTP']._serialized_start=37 36 | _globals['_HTTP']._serialized_end=158 37 | _globals['_HTTPRULE']._serialized_start=161 38 | _globals['_HTTPRULE']._serialized_end=507 39 | _globals['_CUSTOMHTTPPATTERN']._serialized_start=509 40 | _globals['_CUSTOMHTTPPATTERN']._serialized_end=568 41 | # @@protoc_insertion_point(module_scope) 42 | -------------------------------------------------------------------------------- /google/rpc/status_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: google/rpc/status.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'google/rpc/status.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2 26 | 27 | 28 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17google/rpc/status.proto\x12\ngoogle.rpc\x1a\x19google/protobuf/any.proto\"f\n\x06Status\x12\x12\n\x04\x63ode\x18\x01 \x01(\x05R\x04\x63ode\x12\x18\n\x07message\x18\x02 \x01(\tR\x07message\x12.\n\x07\x64\x65tails\x18\x03 \x03(\x0b\x32\x14.google.protobuf.AnyR\x07\x64\x65tailsBa\n\x0e\x63om.google.rpcB\x0bStatusProtoP\x01Z7google.golang.org/genproto/googleapis/rpc/status;status\xf8\x01\x01\xa2\x02\x03RPCb\x06proto3') 29 | 30 | _globals = globals() 31 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 32 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'google.rpc.status_pb2', _globals) 33 | if not _descriptor._USE_C_DESCRIPTORS: 34 | _globals['DESCRIPTOR']._loaded_options = None 35 | _globals['DESCRIPTOR']._serialized_options = b'\n\016com.google.rpcB\013StatusProtoP\001Z7google.golang.org/genproto/googleapis/rpc/status;status\370\001\001\242\002\003RPC' 36 | _globals['_STATUS']._serialized_start=66 37 | _globals['_STATUS']._serialized_end=168 38 | # @@protoc_insertion_point(module_scope) 39 | -------------------------------------------------------------------------------- /google/rpc/status_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | Copyright 2025 Google LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | """ 18 | 19 | import builtins 20 | import collections.abc 21 | import google.protobuf.any_pb2 22 | import google.protobuf.descriptor 23 | import google.protobuf.internal.containers 24 | import google.protobuf.message 25 | import typing 26 | 27 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 28 | 29 | @typing.final 30 | class Status(google.protobuf.message.Message): 31 | """The `Status` type defines a logical error model that is suitable for 32 | different programming environments, including REST APIs and RPC APIs. It is 33 | used by [gRPC](https://github.com/grpc). Each `Status` message contains 34 | three pieces of data: error code, error message, and error details. 35 | 36 | You can find out more about this error model and how to work with it in the 37 | [API Design Guide](https://cloud.google.com/apis/design/errors). 38 | """ 39 | 40 | DESCRIPTOR: google.protobuf.descriptor.Descriptor 41 | 42 | CODE_FIELD_NUMBER: builtins.int 43 | MESSAGE_FIELD_NUMBER: builtins.int 44 | DETAILS_FIELD_NUMBER: builtins.int 45 | code: builtins.int 46 | """The status code, which should be an enum value of 47 | [google.rpc.Code][google.rpc.Code]. 48 | """ 49 | message: builtins.str 50 | """A developer-facing error message, which should be in English. Any 51 | user-facing error message should be localized and sent in the 52 | [google.rpc.Status.details][google.rpc.Status.details] field, or localized 53 | by the client. 54 | """ 55 | @property 56 | def details(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[google.protobuf.any_pb2.Any]: 57 | """A list of messages that carry the error details. There is a common set of 58 | message types for APIs to use. 59 | """ 60 | 61 | def __init__( 62 | self, 63 | *, 64 | code: builtins.int = ..., 65 | message: builtins.str = ..., 66 | details: collections.abc.Iterable[google.protobuf.any_pb2.Any] | None = ..., 67 | ) -> None: ... 68 | def ClearField(self, field_name: typing.Literal["code", b"code", "details", b"details", "message", b"message"]) -> None: ... 69 | 70 | global___Status = Status 71 | -------------------------------------------------------------------------------- /grpcutil/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import grpc 4 | 5 | 6 | def bearer_token_credentials(token: str, certChain: Optional[bytes] = None): 7 | """ 8 | gRPC credentials for a service that requires a Bearer Token. 9 | """ 10 | return grpc.composite_channel_credentials( 11 | grpc.ssl_channel_credentials(root_certificates=certChain), 12 | grpc.access_token_call_credentials(token), 13 | ) 14 | 15 | 16 | def insecure_bearer_token_credentials(token: str): 17 | """ 18 | gRPC credentials for an insecure service that requires a Bearer Token. 19 | 20 | This should only be used for testing. 21 | """ 22 | return grpc.composite_channel_credentials( 23 | grpc.local_channel_credentials(grpc.LocalConnectionType.LOCAL_TCP), 24 | grpc.access_token_call_credentials(token), 25 | ) 26 | -------------------------------------------------------------------------------- /protoc_gen_openapiv2/options/annotations_pb2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by the protocol buffer compiler. DO NOT EDIT! 3 | # NO CHECKED-IN PROTOBUF GENCODE 4 | # source: protoc-gen-openapiv2/options/annotations.proto 5 | # Protobuf Python Version: 5.28.3 6 | """Generated protocol buffer code.""" 7 | from google.protobuf import descriptor as _descriptor 8 | from google.protobuf import descriptor_pool as _descriptor_pool 9 | from google.protobuf import runtime_version as _runtime_version 10 | from google.protobuf import symbol_database as _symbol_database 11 | from google.protobuf.internal import builder as _builder 12 | _runtime_version.ValidateProtobufRuntimeVersion( 13 | _runtime_version.Domain.PUBLIC, 14 | 5, 15 | 28, 16 | 3, 17 | '', 18 | 'protoc-gen-openapiv2/options/annotations.proto' 19 | ) 20 | # @@protoc_insertion_point(imports) 21 | 22 | _sym_db = _symbol_database.Default() 23 | 24 | 25 | from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2 26 | from protoc_gen_openapiv2.options import openapiv2_pb2 as protoc__gen__openapiv2_dot_options_dot_openapiv2__pb2 27 | 28 | 29 | DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n.protoc-gen-openapiv2/options/annotations.proto\x12)grpc.gateway.protoc_gen_openapiv2.options\x1a google/protobuf/descriptor.proto\x1a,protoc-gen-openapiv2/options/openapiv2.proto:~\n\x11openapiv2_swagger\x12\x1c.google.protobuf.FileOptions\x18\x92\x08 \x01(\x0b\x32\x32.grpc.gateway.protoc_gen_openapiv2.options.SwaggerR\x10openapiv2Swagger:\x86\x01\n\x13openapiv2_operation\x12\x1e.google.protobuf.MethodOptions\x18\x92\x08 \x01(\x0b\x32\x34.grpc.gateway.protoc_gen_openapiv2.options.OperationR\x12openapiv2Operation:~\n\x10openapiv2_schema\x12\x1f.google.protobuf.MessageOptions\x18\x92\x08 \x01(\x0b\x32\x31.grpc.gateway.protoc_gen_openapiv2.options.SchemaR\x0fopenapiv2Schema:{\n\x0eopenapiv2_enum\x12\x1c.google.protobuf.EnumOptions\x18\x92\x08 \x01(\x0b\x32\x35.grpc.gateway.protoc_gen_openapiv2.options.EnumSchemaR\ropenapiv2Enum:u\n\ropenapiv2_tag\x12\x1f.google.protobuf.ServiceOptions\x18\x92\x08 \x01(\x0b\x32..grpc.gateway.protoc_gen_openapiv2.options.TagR\x0copenapiv2Tag:~\n\x0fopenapiv2_field\x12\x1d.google.protobuf.FieldOptions\x18\x92\x08 \x01(\x0b\x32\x35.grpc.gateway.protoc_gen_openapiv2.options.JSONSchemaR\x0eopenapiv2FieldBHZFgithub.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/optionsb\x06proto3') 30 | 31 | _globals = globals() 32 | _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) 33 | _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'protoc_gen_openapiv2.options.annotations_pb2', _globals) 34 | if not _descriptor._USE_C_DESCRIPTORS: 35 | _globals['DESCRIPTOR']._loaded_options = None 36 | _globals['DESCRIPTOR']._serialized_options = b'ZFgithub.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options' 37 | # @@protoc_insertion_point(module_scope) 38 | -------------------------------------------------------------------------------- /protoc_gen_openapiv2/options/annotations_pb2.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | @generated by mypy-protobuf. Do not edit manually! 3 | isort:skip_file 4 | """ 5 | 6 | import builtins 7 | import google.protobuf.descriptor 8 | import google.protobuf.descriptor_pb2 9 | import google.protobuf.internal.extension_dict 10 | import protoc_gen_openapiv2.options.openapiv2_pb2 11 | 12 | DESCRIPTOR: google.protobuf.descriptor.FileDescriptor 13 | 14 | OPENAPIV2_SWAGGER_FIELD_NUMBER: builtins.int 15 | OPENAPIV2_OPERATION_FIELD_NUMBER: builtins.int 16 | OPENAPIV2_SCHEMA_FIELD_NUMBER: builtins.int 17 | OPENAPIV2_ENUM_FIELD_NUMBER: builtins.int 18 | OPENAPIV2_TAG_FIELD_NUMBER: builtins.int 19 | OPENAPIV2_FIELD_FIELD_NUMBER: builtins.int 20 | openapiv2_swagger: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FileOptions, protoc_gen_openapiv2.options.openapiv2_pb2.Swagger] 21 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 22 | 23 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 24 | different descriptor messages. 25 | """ 26 | openapiv2_operation: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MethodOptions, protoc_gen_openapiv2.options.openapiv2_pb2.Operation] 27 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 28 | 29 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 30 | different descriptor messages. 31 | """ 32 | openapiv2_schema: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, protoc_gen_openapiv2.options.openapiv2_pb2.Schema] 33 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 34 | 35 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 36 | different descriptor messages. 37 | """ 38 | openapiv2_enum: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.EnumOptions, protoc_gen_openapiv2.options.openapiv2_pb2.EnumSchema] 39 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 40 | 41 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 42 | different descriptor messages. 43 | """ 44 | openapiv2_tag: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.ServiceOptions, protoc_gen_openapiv2.options.openapiv2_pb2.Tag] 45 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 46 | 47 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 48 | different descriptor messages. 49 | """ 50 | openapiv2_field: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FieldOptions, protoc_gen_openapiv2.options.openapiv2_pb2.JSONSchema] 51 | """ID assigned by protobuf-global-extension-registry@google.com for gRPC-Gateway project. 52 | 53 | All IDs are the same, as assigned. It is okay that they are the same, as they extend 54 | different descriptor messages. 55 | """ 56 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | authors = ["Authzed "] 3 | description = "Client library for SpiceDB." 4 | 5 | name = "authzed" 6 | # The version is set at publish time with a call to `poetry version -s `, 7 | # where the tag comes from the release. 8 | version = "0.0.0" 9 | packages = [ 10 | {include = "authzed"}, 11 | # This is the protovalidate-related code 12 | {include = "buf"}, 13 | # NOTE: this is the old validate package that won't be used, 14 | # but the code generated by it is referenced in the generated protobuf/gRPC code. 15 | {include = "validate"}, 16 | {include = "grpcutil"}, 17 | ] 18 | readme = "README.md" 19 | 20 | [tool.poetry.dependencies] 21 | grpcio = "^1.63" 22 | protobuf = ">=5.26,<6" 23 | python = "^3.9" 24 | grpc-interceptor = "^0.15.4" 25 | googleapis-common-protos = "^1.65.0" 26 | protovalidate = "^0.7.1" 27 | 28 | [tool.poetry.group.dev.dependencies] 29 | black = ">=23.3,<26.0" 30 | grpc-stubs = "^1.53" 31 | grpcio-tools = ">=1.63,<1.71" 32 | isort = ">=5.6.4,<7.0.0" 33 | mypy = "1.15.0" 34 | mypy-protobuf = "3.6.0" 35 | mock = "^5.1.0" 36 | pyflakes = "^3.0.1" 37 | pytest = ">=7.1.3,<9.0.0" 38 | pytest-asyncio = ">=0.21,<0.27" 39 | types-protobuf = ">=5.26,<6.0" 40 | typing-extensions = ">=3.7.4,<5" 41 | 42 | [tool.black] 43 | exclude = '(^\.(.*)|^(.*)_pb2(_grpc)?\.py)' 44 | line-length = 100 45 | 46 | [tool.mypy] 47 | explicit_package_bases = true 48 | 49 | [[tool.mypy.overrides]] 50 | ignore_missing_imports = true 51 | module = ["google.rpc.*", "grpcutil"] 52 | 53 | [tool.pytest.ini_options] 54 | addopts = "-x" 55 | log_level = "debug" 56 | minversion = "6.0" 57 | asyncio_mode = "auto" 58 | 59 | [tool.isort] 60 | ensure_newline_before_comments = true 61 | force_grid_wrap = 0 62 | include_trailing_comma = true 63 | line_length = 100 64 | multi_line_output = 3 65 | use_parentheses = true 66 | 67 | [build-system] 68 | build-backend = "poetry.core.masonry.api" 69 | requires = ["poetry-core>=1.0.0"] 70 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/authzed/authzed-py/c99293eb1c74b22748e572c46f587e746cd290a4/tests/__init__.py -------------------------------------------------------------------------------- /tests/calls.py: -------------------------------------------------------------------------------- 1 | from authzed.api.v1 import WriteSchemaRequest 2 | 3 | from .utils import maybe_await 4 | 5 | 6 | async def write_test_schema(client): 7 | schema = """ 8 | caveat likes_harry_potter(likes bool) { 9 | likes == true 10 | } 11 | 12 | definition post { 13 | relation writer: user 14 | relation reader: user 15 | relation caveated_reader: user with likes_harry_potter 16 | 17 | permission write = writer 18 | permission view = reader + writer 19 | permission view_as_fan = caveated_reader + writer 20 | } 21 | definition user {} 22 | """ 23 | await maybe_await(client.WriteSchema(WriteSchemaRequest(schema=schema))) 24 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | import pytest 4 | 5 | 6 | @pytest.fixture(scope="function") 7 | def token(): 8 | return str(uuid.uuid4()) 9 | -------------------------------------------------------------------------------- /tests/insecure_client_test.py: -------------------------------------------------------------------------------- 1 | import grpc 2 | import pytest 3 | 4 | from authzed.api.v1 import AsyncClient, InsecureClient, SyncClient 5 | from grpcutil import insecure_bearer_token_credentials 6 | 7 | from .calls import write_test_schema 8 | 9 | ## NOTE: these tests aren't usually run. They theoretically could and theoretically 10 | # should be run in CI, but getting an appropriate "remote" container is difficult with 11 | # github actions; this will happen at some point in the future. 12 | # To run them: `poetry run pytest -m ""` 13 | 14 | # NOTE: this is the name of the "remote" binding of the service container 15 | # in CI. These tests are only run in CI because otherwise setup is fiddly. 16 | # If you want to see these tests run locally, figure out your computer's 17 | # network-local IP address (typically 192.168.x.x) and make that the `remote_host` 18 | # string below, and then start up a testing container bound to that interface: 19 | # docker run --rm -p 192.168.x.x:50051:50051 authzed/spicedb serve-testing 20 | remote_host = "192.168.something.something" 21 | 22 | 23 | @pytest.mark.skip(reason="Makes a remote call that we haven't yet supported in CI") 24 | async def test_normal_async_client_raises_error_on_insecure_remote_call(token): 25 | with pytest.raises(grpc.RpcError): 26 | client = AsyncClient(f"{remote_host}:50051", insecure_bearer_token_credentials(token)) 27 | await write_test_schema(client) 28 | 29 | 30 | @pytest.mark.skip(reason="Makes a remote call that we haven't yet supported in CI") 31 | async def test_normal_sync_client_raises_error_on_insecure_remote_call(token): 32 | with pytest.raises(grpc.RpcError): 33 | client = SyncClient(f"{remote_host}:50051", insecure_bearer_token_credentials(token)) 34 | await write_test_schema(client) 35 | 36 | 37 | @pytest.mark.skip(reason="Makes a remote call that we haven't yet supported in CI") 38 | async def test_insecure_client_makes_insecure_remote_call(token): 39 | insecure_client = InsecureClient(f"{remote_host}:50051", token) 40 | await write_test_schema(insecure_client) 41 | -------------------------------------------------------------------------------- /tests/misc_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from protovalidate import ValidationError, validate 3 | 4 | from authzed.api.v1 import ObjectReference, Relationship 5 | 6 | 7 | def test_type_error_does_not_segfault(): 8 | with pytest.raises(TypeError): 9 | res = ObjectReference(object_type="post", object_id="post-one") 10 | Relationship( 11 | resource=res, 12 | relation="writer", 13 | subject=res, 14 | ) 15 | 16 | 17 | def test_validate(): 18 | with pytest.raises(ValidationError): 19 | validate(ObjectReference(object_type="post", object_id="@#¢∞¬÷“”")) 20 | 21 | validate(ObjectReference(object_type="post", object_id="test")) 22 | -------------------------------------------------------------------------------- /tests/utils.py: -------------------------------------------------------------------------------- 1 | from inspect import isawaitable 2 | from typing import AsyncIterable, Iterable, List, TypeVar, Union 3 | 4 | T = TypeVar("T") 5 | 6 | 7 | async def maybe_async_iterable_to_list(iterable: Union[Iterable[T], AsyncIterable[T]]) -> List[T]: 8 | items = [] 9 | if isinstance(iterable, AsyncIterable): 10 | async for item in iterable: 11 | items.append(item) 12 | else: 13 | for item in iterable: 14 | items.append(item) 15 | return items 16 | 17 | 18 | async def maybe_await(resp: T) -> T: 19 | if isawaitable(resp): 20 | resp = await resp 21 | return resp 22 | --------------------------------------------------------------------------------