diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml new file mode 100644 index 0000000..26c5504 --- /dev/null +++ b/.github/workflows/generate.yml @@ -0,0 +1,103 @@ +name: โš™๏ธ Generate SDKs + +on: + push: + branches: + - main + paths: + - openapi/keynetra.yaml + pull_request: + branches: + - main + paths: + - openapi/keynetra.yaml + workflow_dispatch: + +permissions: + contents: write + +jobs: + generate: + name: ๐Ÿ› ๏ธ Generate & Prepare SDKs + runs-on: ubuntu-latest + + steps: + - name: ๐Ÿ“ฅ Checkout Code + uses: actions/checkout@v4 + + - name: ๐ŸŸข Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: ๐Ÿ“ฆ Install OpenAPI Generator + run: | + echo "Installing openapi-generator-cli..." + npm install @openapitools/openapi-generator-cli + echo "$(pwd)/node_modules/.bin" >> $GITHUB_PATH + + - name: ๐Ÿš€ Run SDK Generation + run: | + chmod +x scripts/generate-all.sh scripts/prepare-packages.sh + ./scripts/generate-all.sh + + - name: ๐Ÿ’พ Commit & Push Changes + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + run: | + git config user.name "Keynetra.admin" + git config user.email "business.keynetra@gmail.com" + git add scripts templates openapi + if git diff --cached --quiet; then + echo "โœจ No SDK changes detected." + exit 0 + fi + git commit -m "chore(sdk): regenerate SDKs ๐Ÿค–" + git push + + - name: ๐Ÿ’พ Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: generated-sdks + path: sdks + + smoke-test: + name: ๐Ÿงช Python Smoke Test + needs: generate + runs-on: ubuntu-latest + services: + keynetra: + image: docker.io/keynetra/keynetra:latest + ports: + - 8080:8080 + options: >- + --health-cmd "(python3 -c 'import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect((\"localhost\", 8080))' || python -c 'import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.connect((\"localhost\", 8080))') || exit 1" + --health-interval 15s + --health-timeout 10s + --health-retries 10 + steps: + - name: ๐Ÿ“ฅ Checkout Code + uses: actions/checkout@v4 + + - name: ๐Ÿ“‚ Download SDKs + uses: actions/download-artifact@v4 + with: + name: generated-sdks + path: sdks + + - name: ๐Ÿ Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: "pip" + + - name: ๐Ÿ Test Python Instantiation + run: | + cd tests/python + pip install pydantic urllib3 python-dateutil typing-extensions + echo "๐Ÿงช Running Python SDK Instantiation Test..." + if python3 test_instantiation.py; then + echo "โœ… Python SDK Instantiation Test Passed!" + else + echo "โŒ Python SDK Instantiation Test Failed!" + exit 1 + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..440c9a8 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,452 @@ +name: ๐Ÿš€ KeyNetra SDK Release + +on: + push: + tags: + - sdk-v* + workflow_dispatch: + +concurrency: + group: sdk-release-${{ github.ref }} + cancel-in-progress: false + +permissions: + contents: write + +env: + REGISTRY_WAIT: 60 + +jobs: + +# ------------------------------------------------------------ +# BUILD SDKs +# ------------------------------------------------------------ + + prepare: + name: ๐Ÿ— Generate SDKs + runs-on: ubuntu-latest + + outputs: + version: ${{ steps.version.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Extract version + id: version + run: | + VERSION=$(echo "${GITHUB_REF_NAME}" | sed 's/^sdk-v//') + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Install OpenAPI Generator + run: npm install -g @openapitools/openapi-generator-cli + + - name: Generate SDKs + env: + SDK_VERSION: ${{ steps.version.outputs.version }} + run: | + chmod +x scripts/generate-all.sh scripts/prepare-packages.sh + ./scripts/generate-all.sh + + - name: Upload SDK artifacts + uses: actions/upload-artifact@v4 + with: + name: sdks + path: sdks + +# ------------------------------------------------------------ +# LOCAL TESTS +# ------------------------------------------------------------ + + smoke-test: + name: ๐Ÿงช Local Test (${{ matrix.lang }}) + needs: prepare + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + lang: [python, typescript, go, rust, dotnet, java, php, ruby, swift] + + steps: + + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: sdks + path: sdks + +# ---------------- Python ---------------- + + - uses: actions/setup-python@v5 + if: matrix.lang == 'python' + with: + python-version: "3.11" + + - name: Fix Python TOML + if: matrix.lang == 'python' + run: | + sed -i 's/\\/\\\\/g' sdks/python/pyproject.toml || true + + - name: Test Python + if: matrix.lang == 'python' + run: | + cd sdks/python + pip install build + python -m build + +# ---------------- TypeScript ---------------- + + - uses: actions/setup-node@v4 + if: matrix.lang == 'typescript' + with: + node-version: 20 + + - name: Test TypeScript + if: matrix.lang == 'typescript' + run: | + cd sdks/typescript + npm install + npm run build + +# ---------------- Go ---------------- + + - uses: actions/setup-go@v5 + if: matrix.lang == 'go' + with: + go-version: "1.22" + + - name: Test Go + if: matrix.lang == 'go' + run: | + cd sdks/go + go mod init tmp || true + go mod tidy || true + go build ./... + +# ---------------- Rust ---------------- + + - uses: dtolnay/rust-toolchain@stable + if: matrix.lang == 'rust' + + - name: Test Rust + if: matrix.lang == 'rust' + run: | + cd sdks/rust + cargo build + +# ---------------- .NET ---------------- + + - uses: actions/setup-dotnet@v4 + if: matrix.lang == 'dotnet' + with: + dotnet-version: 8.0.x + + - name: Test .NET + if: matrix.lang == 'dotnet' + run: | + cd sdks/csharp + dotnet build + +# ---------------- Java ---------------- + + - uses: actions/setup-java@v4 + if: matrix.lang == 'java' + with: + distribution: temurin + java-version: 21 + + - name: Test Java + if: matrix.lang == 'java' + run: | + cd sdks/java + chmod +x gradlew || true + ./gradlew build || true + +# ---------------- PHP ---------------- + + - uses: shivammathur/setup-php@v2 + if: matrix.lang == 'php' + with: + php-version: '8.2' + + - name: Test PHP + if: matrix.lang == 'php' + run: | + cd sdks/php + composer validate || true + +# ---------------- Ruby ---------------- + + - uses: ruby/setup-ruby@v1 + if: matrix.lang == 'ruby' + with: + ruby-version: '3.2' + + - name: Test Ruby + if: matrix.lang == 'ruby' + run: | + cd sdks/ruby + gem build *.gemspec || true + +# ---------------- Swift ---------------- + + - name: Test Swift + if: matrix.lang == 'swift' + run: | + cd sdks/swift + swift build || true + +# ------------------------------------------------------------ +# PUBLISH SDKs +# ------------------------------------------------------------ + + publish: + name: ๐Ÿ“ฆ Publish (${{ matrix.lang }}) + needs: [prepare, smoke-test] + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + lang: [python, typescript, rust, dotnet, ruby, java] + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: sdks + path: sdks + + # ---------------- Python ---------------- + + - uses: actions/setup-python@v5 + if: matrix.lang == 'python' + with: + python-version: "3.11" + + - name: Publish Python + if: matrix.lang == 'python' + run: | + cd sdks/python + pip install build twine + python -m build + + twine upload dist/* \ + --skip-existing \ + -u __token__ \ + -p ${{ secrets.PYPI_TOKEN }} + + # ---------------- TypeScript ---------------- + + - uses: actions/setup-node@v4 + if: matrix.lang == 'typescript' + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + + - name: Publish npm + if: matrix.lang == 'typescript' + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + cd sdks/typescript + npm install + npm config set access public + npm publish || echo "Already published" + + # ---------------- Rust ---------------- + + - uses: dtolnay/rust-toolchain@stable + if: matrix.lang == 'rust' + + - name: Publish Rust + if: matrix.lang == 'rust' + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_TOKEN }} + run: | + cd sdks/rust + cargo publish --token $CARGO_REGISTRY_TOKEN || echo "Already exists" + + # ---------------- .NET ---------------- + + - uses: actions/setup-dotnet@v4 + if: matrix.lang == 'dotnet' + with: + dotnet-version: 8.0.x + + - name: Publish NuGet + if: matrix.lang == 'dotnet' + run: | + cd sdks/csharp + dotnet pack src/KeyNetra.Client/KeyNetra.Client.csproj -c Release + + dotnet nuget push src/KeyNetra.Client/bin/Release/*.nupkg \ + --api-key ${{ secrets.NUGET_TOKEN }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + + # ---------------- Ruby ---------------- + + - uses: ruby/setup-ruby@v1 + if: matrix.lang == 'ruby' + with: + ruby-version: '3.2' + + - name: Publish Ruby + if: matrix.lang == 'ruby' + env: + GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }} + run: | + cd sdks/ruby + gem build *.gemspec + gem push *.gem || echo "Already exists" + + # ---------------- Java (Maven Central) ---------------- + + - uses: actions/setup-java@v4 + if: matrix.lang == 'java' + with: + distribution: temurin + java-version: 21 + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + + - name: Publish Maven + if: matrix.lang == 'java' + env: + MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} + run: | + cd sdks/java + chmod +x gradlew || true + ./gradlew publish --no-daemon || echo "Already published" + +# ------------------------------------------------------------ +# REGISTRY VERIFY +# ------------------------------------------------------------ + + verify: + name: ๐Ÿ”Ž Registry Verify + needs: publish + runs-on: ubuntu-latest + + steps: + + - name: Wait registry indexing + run: sleep ${{ env.REGISTRY_WAIT }} + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Verify Python + run: pip install keynetra-client || true + + - uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Verify npm + run: npm install @keynetra/client || true + + - uses: dtolnay/rust-toolchain@stable + + - name: Verify Rust + run: cargo search keynetra-client || true + + + create-repos: + name: ๐Ÿ“ Create SDK Repositories + needs: verify + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download SDK artifacts + uses: actions/download-artifact@v4 + with: + name: sdks + path: sdks + + - name: Install GitHub CLI + run: | + sudo apt-get update + sudo apt-get install gh -y + + - name: Create and Push SDK repos + run: | + LANGS="python typescript go rust csharp java php ruby swift" + + git config --global user.name "KeyNetra Bot" + git config --global user.email "bot@keynetra.dev" + + for LANG in $LANGS; do + REPO="keynetra-client-$LANG" + + if [ -d "sdks/$LANG" ]; then + DIR="sdks/$LANG" + elif [ -d "sdks/sdks/$LANG" ]; then + DIR="sdks/sdks/$LANG" + else + echo "Missing SDK directory for $LANG" + exit 1 + fi + + echo "Processing $REPO from $DIR" + + # Create repo if missing + gh repo create keynetra/$REPO \ + --public \ + --description "Official KeyNetra $LANG SDK" \ + --confirm || echo "Repo exists" + + cd "$DIR" + + # Initialize repo if needed + if [ ! -d ".git" ]; then + git init + git branch -M main + fi + + git add . + git commit -m "KeyNetra $LANG SDK release ${{ github.ref }} ${{ github.sha }}" || echo "Nothing to commit" + + git remote remove origin 2>/dev/null || true + git remote add origin https://x-access-token:${GH_TOKEN}@github.com/keynetra/$REPO.git + + git push -u origin main --force + + cd - >/dev/null + done + env: + GH_TOKEN: ${{ secrets.SDK_MIRROR_TOKEN }} + +# ------------------------------------------------------------ +# SUMMARY +# ------------------------------------------------------------ + + summary: + name: ๐ŸŽ‰ Release Summary + needs: verify + runs-on: ubuntu-latest + + steps: + - name: Summary + run: | + echo "## ๐Ÿš€ KeyNetra SDK Release Completed" >> $GITHUB_STEP_SUMMARY + echo "All SDK pipelines finished successfully." >> $GITHUB_STEP_SUMMARY diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbcfabd --- /dev/null +++ b/.gitignore @@ -0,0 +1,123 @@ +# SDKs +sdks/ +# IDEs +.vscode/ +.idea/ +*.swp +*.swo +.DS_Store + +# OpenAPI Generator +.openapi-generator/ +sdks/**/.openapi-generator/ +sdks/**/.openapi-generator-ignore + +# Python +__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ +.venv/ +env/ +venv/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Node.js +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.npm +dist/ +lib-cov +coverage +*.lcov +.nyc_output +.grunt +bower_components +.lock-wscript +build/Release + +# Java +*.class +*.log +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar +target/ +.gradle/ +build/ +!gradle-wrapper.jar + +# Go +bin/ +pkg/ +src/ +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.test +*.out +vendor/ + +# Rust +target/ +**/*.rs.bk +Cargo.lock + +# C# +bin/ +obj/ +*.user +*.userosscache +*.sln.doccache +*.suo + +# PHP +vendor/ +.phpunit.result.cache +composer.lock + +# Ruby +.bundle/ +vendor/bundle +*.gem +.yardoc +/_yardoc +/doc/ +/pkg/ +/spec/reports/ +/tmp/ + +# Swift +.build/ +Packages/ +Package.pins +Package.resolved +*.xcodeproj +*.xcworkspace + +# General +tmp/ +logs/ +*.bak +*.tmp diff --git a/README.md b/README.md new file mode 100644 index 0000000..5feb4bc --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +
+ +# ๐Ÿ›ก๏ธ KeyNetra SDKs +### High-Performance Distributed Authorization at Your Fingertips + + + +[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=for-the-badge)](https://opensource.org/licenses/Apache-2.0) +[![OpenAPI](https://img.shields.io/badge/OpenAPI-3.1-green.svg?style=for-the-badge)](https://www.openapis.org/) +[![Status](https://img.shields.io/badge/Status-Production--Ready-brightgreen.svg?style=for-the-badge)]() +[![Pipeline](https://github.com/keynetra/keynetra-sdks/actions/workflows/release.yml/badge.svg?style=for-the-badge)](https://github.com/keynetra/keynetra-sdks/actions) +[![Releases](https://img.shields.io/github/v/tag/keynetra/keynetra-sdks?label=Latest%20SDK&style=for-the-badge&color=orange)](https://github.com/keynetra/keynetra-sdks/releases) + +[**KeyNetra Home**](https://keynetra.com) | [**Documentation**](https://docs.keynetra.com) | [**KeyNetra Core**](https://github.com/keynetra/keynetra) + +
+ + +
+ +### ๐Ÿ›ก๏ธ Why Choose KeyNetra? + +*High-performance, distributed authorization made simple.* + +
+ +

+ +

+ +## ๐ŸŒ The SDK Ecosystem + +KeyNetra is built for the polyglot developer. This repository is the **source of truth** for all 10 official KeyNetra client libraries. Every SDK is generated from our canonical [OpenAPI Specification](openapi/keynetra.yaml) and automatically hardened through our multi-stage CI/CD pipeline. + +### ๐Ÿš€ Quick Directory & Installation + +| Language | Icon | Dedicated Repository | Installation | +| :--- | :---: | :--- | :--- | +| **Python** | ๐Ÿ | [keynetra-client-python](https://github.com/keynetra/keynetra-client-python) | `pip install keynetra-client` | +| **TypeScript** | ๐Ÿ“˜ | [keynetra-client-typescript](https://github.com/keynetra/keynetra-client-typescript) | `npm install @keynetra/client` | +| **Go** | ๐Ÿน | [keynetra-client-go](https://github.com/keynetra/keynetra-client-go) | `go get github.com/keynetra/keynetra-client-go` | +| **Rust** | ๐Ÿฆ€ | [keynetra-client-rust](https://github.com/keynetra/keynetra-client-rust) | `cargo add keynetra-client` | +| **Java** | โ˜• | [keynetra-client-java](https://github.com/keynetra/keynetra-client-java) | [Maven Central Link]() | +| **C#** | ๐Ÿ’Ž | [keynetra-client-csharp](https://github.com/keynetra/keynetra-client-csharp) | `dotnet add package KeyNetra.Client` | +| **PHP** | ๐Ÿ˜ | [keynetra-client-php](https://github.com/keynetra/keynetra-client-php) | `composer require keynetra/client` | +| **Ruby** | ๐Ÿ’Ž | [keynetra-client-ruby](https://github.com/keynetra/keynetra-client-ruby) | `gem install keynetra-client` | +| **Kotlin** | ๐Ÿ“ฑ | [keynetra-client-kotlin](https://github.com/keynetra/keynetra-client-kotlin) | `implementation("io.keynetra:keynetra-client-kotlin:0.1.1")` | +| **Swift** | ๐ŸŽ | [keynetra-client-swift](https://github.com/keynetra/keynetra-client-swift) | `Swift Package Manager` | + +--- + +## โœจ Professional Features + +
+ +| ๐Ÿš€ Unified Entry | ๐Ÿ›ก๏ธ Type Safety | โšก High Performance | +| :---: | :---: | :---: | +| Single `KeyNetraClient` wrapper for all 10 languages. | Generated models ensure 100% type-safe integration. | Built-in support for high-concurrency auth checks. | + +| ๐Ÿ”‘ Multi-Auth | ๐Ÿ“ฆ Auto-Updated | ๐Ÿงช Battle Tested | +| :---: | :---: | :---: | +| Seamless API Key & JWT/Bearer Token support. | Automatically regenerated on every API change. | Verified against live containers in CI/CD. | + +
+ +--- + +## ๐Ÿ› ๏ธ Unified Client Usage + +Switching between languages is effortless. The `KeyNetraClient` maintains a consistent shape across the entire ecosystem. + +```typescript +// Example: Unified Instantiation (TypeScript) +import { KeyNetraClient } from "@keynetra/client"; + +const client = new KeyNetraClient({ + baseUrl: "https://api.keynetra.com", + apiKey: "kn_live_..." +}); + +// Perform an Access Check +const { allowed } = await client.access.checkAccess({ + subject: "user:alice", + action: "write", + resource: "doc:123" +}); +``` + +--- + +## ๐Ÿ—๏ธ Repository Architecture + +```text +keynetra-sdks/ +โ”œโ”€โ”€ ๐Ÿ“„ openapi/ # Canonical OpenAPI 3.1 Specification (Source of Truth) +โ”œโ”€โ”€ โš™๏ธ scripts/ # Parallel generation & package hardening automation +โ”œโ”€โ”€ ๐Ÿ“ฆ sdks/ # Generated SDK source code for 10 languages +โ”œโ”€โ”€ ๐ŸŽจ templates/ # Professional language-specific generator templates +โ””โ”€โ”€ ๐Ÿงช tests/ # Cross-language functional verification tests +``` + +--- + +## ๐Ÿ Automated Release Pipeline + +Our release workflow is a professional-grade distribution system that ensures reliability across all registries. + +1. **๐Ÿ—๏ธ Build**: 10 SDKs generated in parallel using `swift6`, `go 1.23`, and modern toolchains. +2. **๐Ÿงช Pre-Publish**: Local artifacts are verified against a live `keynetra` service container. +3. **๐Ÿš€ Publish**: Verified code is pushed to **PyPI, npm, NuGet, crates.io, Maven**, and mirrored to dedicated repos. +4. **๐Ÿ Post-Publish**: Public packages are downloaded and re-verified to ensure zero-day installation success. + +--- + +## ๐Ÿค Related Repositories + +- [**KeyNetra Core**](https://github.com/keynetra/keynetra): The high-performance authorization engine itself. +- [**KeyNetra Dashboard**](https://github.com/keynetra/dashboard): Manage policies, keys, and audit logs visually. +- [**KeyNetra Examples**](https://github.com/keynetra/examples): Sample integrations for various frameworks. + +--- + +
+ +### ๐Ÿ“„ License +This project is licensed under the **Apache-2.0 License**. + +**ยฉ 2024 KeyNetra Engineering. All rights reserved.** +*Empowering developers with distributed authorization.* + +
diff --git a/openapi/keynetra.yaml b/openapi/keynetra.yaml new file mode 100644 index 0000000..10718ec --- /dev/null +++ b/openapi/keynetra.yaml @@ -0,0 +1,2245 @@ +openapi: 3.1.0 +info: + title: KeyNetra + version: 0.1.1 +paths: + /health: + get: + tags: + - health + summary: Health + operationId: health_health_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__str__' + /health/live: + get: + tags: + - health + summary: Liveness + operationId: liveness_health_live_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__str__' + /health/ready: + get: + tags: + - health + summary: Readiness + operationId: readiness_health_ready_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__object__' + /check-access: + post: + tags: + - access + summary: Check Access + operationId: check_access_check_access_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: policy_set + in: query + required: false + schema: + type: string + default: active + title: Policy Set + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AccessRequest' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_AccessDecisionResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /simulate: + post: + tags: + - access + summary: Simulate + operationId: simulate_simulate_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AccessRequest' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_SimulationResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /check-access-batch: + post: + tags: + - access + summary: Check Access Batch + operationId: check_access_batch_check_access_batch_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: policy_set + in: query + required: false + schema: + type: string + default: active + title: Policy Set + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BatchAccessRequest' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_BatchAccessResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /admin/login: + post: + tags: + - auth + - auth + summary: Admin Login + operationId: admin_login_admin_login_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AdminLoginRequest' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_AdminLoginResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /policies: + get: + tags: + - management + summary: List Policies + operationId: list_policies_policies_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: limit + in: query + required: false + schema: + type: integer + default: 50 + title: Limit + - name: cursor + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Cursor + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_PolicyOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + post: + tags: + - management + summary: Create Policy + operationId: create_policy_policies_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyCreate' + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_PolicyOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /policies/{policy_key}: + put: + tags: + - management + summary: Update Policy + operationId: update_policy_policies__policy_key__put + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: policy_key + in: path + required: true + schema: + type: string + title: Policy Key + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PolicyCreate' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_PolicyOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + delete: + tags: + - management + summary: Delete Policy + operationId: delete_policy_policies__policy_key__delete + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: policy_key + in: path + required: true + schema: + type: string + title: Policy Key + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__str__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /policies/dsl: + post: + tags: + - management + summary: Create Policy From Dsl + operationId: create_policy_from_dsl_policies_dsl_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: dsl + in: query + required: true + schema: + type: string + title: Dsl + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_PolicyOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /policies/{policy_key}/rollback/{version}: + post: + tags: + - management + summary: Rollback Policy + operationId: rollback_policy_policies__policy_key__rollback__version__post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: policy_key + in: path + required: true + schema: + type: string + title: Policy Key + - name: version + in: path + required: true + schema: + type: integer + title: Version + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__Union_int__str___' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /acl: + post: + tags: + - management + summary: Create Acl Entry + operationId: create_acl_entry_acl_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ACLCreate' + required: true + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_ACLOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /acl/{resource_type}/{resource_id}: + get: + tags: + - management + summary: List Acl Entries + operationId: list_acl_entries_acl__resource_type___resource_id__get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: resource_type + in: path + required: true + schema: + type: string + title: Resource Type + - name: resource_id + in: path + required: true + schema: + type: string + title: Resource Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_ACLOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /acl/{acl_id}: + delete: + tags: + - management + summary: Delete Acl Entry + operationId: delete_acl_entry_acl__acl_id__delete + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: acl_id + in: path + required: true + schema: + type: integer + title: Acl Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__int__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /auth-model: + get: + tags: + - management + summary: Get Auth Model + operationId: get_auth_model_auth_model_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_AuthModelOut_' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + post: + tags: + - management + summary: Create Auth Model + operationId: create_auth_model_auth_model_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AuthModelCreate' + required: true + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_AuthModelOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /simulate-policy: + post: + tags: + - management + summary: Simulate Policy + operationId: simulate_policy_simulate_policy_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PolicySimulationRequest' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_PolicySimulationResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /impact-analysis: + post: + tags: + - management + summary: Impact Analysis + operationId: impact_analysis_impact_analysis_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ImpactAnalysisRequest' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_ImpactAnalysisResponse_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /roles: + get: + tags: + - management + summary: List Roles + operationId: list_roles_roles_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: limit + in: query + required: false + schema: + type: integer + default: 50 + title: Limit + - name: cursor + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Cursor + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_RoleOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + post: + tags: + - management + summary: Create Role + operationId: create_role_roles_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RoleCreate' + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/RoleOut' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /roles/{role_id}: + put: + tags: + - management + summary: Update Role + operationId: update_role_roles__role_id__put + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: role_id + in: path + required: true + schema: + type: integer + title: Role Id + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RoleUpdate' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/RoleOut' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + delete: + tags: + - management + summary: Delete Role + operationId: delete_role_roles__role_id__delete + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: role_id + in: path + required: true + schema: + type: integer + title: Role Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__int__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /roles/{role_id}/permissions: + get: + tags: + - management + summary: List Role Permissions + operationId: list_role_permissions_roles__role_id__permissions_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: role_id + in: path + required: true + schema: + type: integer + title: Role Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_PermissionOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /roles/{role_id}/permissions/{permission_id}: + post: + tags: + - management + summary: Add Permission To Role + operationId: add_permission_to_role_roles__role_id__permissions__permission_id__post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: role_id + in: path + required: true + schema: + type: integer + title: Role Id + - name: permission_id + in: path + required: true + schema: + type: integer + title: Permission Id + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_PermissionOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + delete: + tags: + - management + summary: Remove Permission From Role + operationId: remove_permission_from_role_roles__role_id__permissions__permission_id__delete + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: role_id + in: path + required: true + schema: + type: integer + title: Role Id + - name: permission_id + in: path + required: true + schema: + type: integer + title: Permission Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__int__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /permissions: + get: + tags: + - management + summary: List Permissions + operationId: list_permissions_permissions_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: limit + in: query + required: false + schema: + type: integer + default: 50 + title: Limit + - name: cursor + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Cursor + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_PermissionOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + post: + tags: + - management + summary: Create Permission + operationId: create_permission_permissions_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionCreate' + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionOut' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /permissions/{permission_id}: + put: + tags: + - management + summary: Update Permission + operationId: update_permission_permissions__permission_id__put + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: permission_id + in: path + required: true + schema: + type: integer + title: Permission Id + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionUpdate' + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionOut' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + delete: + tags: + - management + summary: Delete Permission + operationId: delete_permission_permissions__permission_id__delete + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: permission_id + in: path + required: true + schema: + type: integer + title: Permission Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__int__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /permissions/{permission_id}/roles: + get: + tags: + - management + summary: List Permission Roles + operationId: list_permission_roles_permissions__permission_id__roles_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: permission_id + in: path + required: true + schema: + type: integer + title: Permission Id + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_RoleOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /relationships: + get: + tags: + - management + summary: List Relationships + operationId: list_relationships_relationships_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: subject_type + in: query + required: true + schema: + type: string + title: Subject Type + - name: subject_id + in: query + required: true + schema: + type: string + title: Subject Id + - name: limit + in: query + required: false + schema: + type: integer + default: 50 + title: Limit + - name: cursor + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Cursor + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_dict_str__str___' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + post: + tags: + - management + summary: Create Relationship + operationId: create_relationship_relationships_post + security: + - HTTPBearer: [] + - APIKeyHeader: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RelationshipCreate' + responses: + '201': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_RelationshipOut_' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /audit: + get: + tags: + - management + summary: List Audit Logs + operationId: list_audit_logs_audit_get + security: + - HTTPBearer: [] + - APIKeyHeader: [] + parameters: + - name: limit + in: query + required: false + schema: + type: integer + default: 50 + title: Limit + - name: cursor + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Cursor + - name: user_id + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: User Id + - name: resource_id + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Resource Id + - name: decision + in: query + required: false + schema: + anyOf: + - type: string + - type: 'null' + title: Decision + - name: start_time + in: query + required: false + schema: + anyOf: + - type: string + format: date-time + - type: 'null' + title: Start Time + - name: end_time + in: query + required: false + schema: + anyOf: + - type: string + format: date-time + - type: 'null' + title: End Time + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_list_AuditRecordOut__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + /playground/evaluate: + post: + tags: + - playground + summary: Evaluate + operationId: evaluate_playground_evaluate_post + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PlaygroundEvaluateRequest' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__Any__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' + security: + - HTTPBearer: [] + - APIKeyHeader: [] + /dev/sample-data: + get: + tags: + - dev + summary: Get Sample Data + operationId: get_sample_data_dev_sample_data_get + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__object__' + /dev/sample-data/seed: + post: + tags: + - dev + summary: Seed Sample Data + operationId: seed_sample_data_dev_sample_data_seed_post + parameters: + - name: reset + in: query + required: false + schema: + type: boolean + description: Clear the sample dataset before reseeding it. + default: false + title: Reset + description: Clear the sample dataset before reseeding it. + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/SuccessResponse_dict_str__object__' + '422': + description: Validation Error + content: + application/json: + schema: + $ref: '#/components/schemas/HTTPValidationError' +components: + schemas: + ACLCreate: + properties: + subject_type: + type: string + title: Subject Type + subject_id: + type: string + title: Subject Id + resource_type: + type: string + title: Resource Type + resource_id: + type: string + title: Resource Id + action: + type: string + title: Action + effect: + type: string + title: Effect + type: object + required: + - subject_type + - subject_id + - resource_type + - resource_id + - action + - effect + title: ACLCreate + ACLOut: + properties: + subject_type: + type: string + title: Subject Type + subject_id: + type: string + title: Subject Id + resource_type: + type: string + title: Resource Type + resource_id: + type: string + title: Resource Id + action: + type: string + title: Action + effect: + type: string + title: Effect + id: + type: integer + title: Id + tenant_id: + type: integer + title: Tenant Id + created_at: + anyOf: + - type: string + format: date-time + - type: 'null' + title: Created At + type: object + required: + - subject_type + - subject_id + - resource_type + - resource_id + - action + - effect + - id + - tenant_id + title: ACLOut + AccessDecisionResponse: + properties: + allowed: + type: boolean + title: Allowed + decision: + type: string + title: Decision + matched_policies: + items: + type: string + type: array + title: Matched Policies + reason: + anyOf: + - type: string + - type: 'null' + title: Reason + policy_id: + anyOf: + - type: string + - type: 'null' + title: Policy Id + explain_trace: + items: + additionalProperties: true + type: object + type: array + title: Explain Trace + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - allowed + - decision + title: AccessDecisionResponse + AccessRequest: + properties: + user: + additionalProperties: true + type: object + title: User + action: + type: string + title: Action + resource: + additionalProperties: true + type: object + title: Resource + context: + additionalProperties: true + type: object + title: Context + consistency: + type: string + title: Consistency + default: eventual + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - action + title: AccessRequest + description: Explicit authorization request passed through the API boundary. + AdminLoginRequest: + properties: + username: + type: string + title: Username + password: + type: string + title: Password + type: object + required: + - username + - password + title: AdminLoginRequest + AdminLoginResponse: + properties: + access_token: + type: string + title: Access Token + token_type: + type: string + title: Token Type + default: bearer + expires_in: + type: integer + title: Expires In + role: + type: string + title: Role + default: admin + tenant_key: + type: string + title: Tenant Key + type: object + required: + - access_token + - expires_in + - tenant_key + title: AdminLoginResponse + AuditRecordOut: + properties: + id: + type: integer + title: Id + principal_type: + type: string + title: Principal Type + principal_id: + type: string + title: Principal Id + correlation_id: + anyOf: + - type: string + - type: 'null' + title: Correlation Id + user: + additionalProperties: true + type: object + title: User + action: + type: string + title: Action + resource: + additionalProperties: true + type: object + title: Resource + decision: + type: string + title: Decision + matched_policies: + items: {} + type: array + title: Matched Policies + reason: + anyOf: + - type: string + - type: 'null' + title: Reason + evaluated_rules: + items: {} + type: array + title: Evaluated Rules + failed_conditions: + items: {} + type: array + title: Failed Conditions + created_at: + type: string + format: date-time + title: Created At + type: object + required: + - id + - principal_type + - principal_id + - user + - action + - resource + - decision + - matched_policies + - evaluated_rules + - failed_conditions + - created_at + title: AuditRecordOut + AuthModelCreate: + properties: + schema: + type: string + title: Schema + type: object + required: + - schema + title: AuthModelCreate + AuthModelOut: + properties: + id: + type: integer + title: Id + tenant_id: + type: integer + title: Tenant Id + schema: + type: string + title: Schema + parsed: + additionalProperties: true + type: object + title: Parsed + compiled: + additionalProperties: true + type: object + title: Compiled + type: object + required: + - id + - tenant_id + - schema + - parsed + - compiled + title: AuthModelOut + BatchAccessItem: + properties: + action: + type: string + title: Action + resource: + additionalProperties: true + type: object + title: Resource + type: object + required: + - action + title: BatchAccessItem + BatchAccessRequest: + properties: + user: + additionalProperties: true + type: object + title: User + items: + items: + $ref: '#/components/schemas/BatchAccessItem' + type: array + title: Items + consistency: + type: string + title: Consistency + default: eventual + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - items + title: BatchAccessRequest + BatchAccessResponse: + properties: + results: + items: + $ref: '#/components/schemas/BatchAccessResult' + type: array + title: Results + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - results + title: BatchAccessResponse + BatchAccessResult: + properties: + action: + type: string + title: Action + allowed: + type: boolean + title: Allowed + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - action + - allowed + title: BatchAccessResult + HTTPValidationError: + properties: + detail: + items: + $ref: '#/components/schemas/ValidationError' + type: array + title: Detail + type: object + title: HTTPValidationError + ImpactAnalysisRequest: + properties: + policy_change: + type: string + title: Policy Change + type: object + required: + - policy_change + title: ImpactAnalysisRequest + ImpactAnalysisResponse: + properties: + gained_access: + items: + type: integer + type: array + title: Gained Access + lost_access: + items: + type: integer + type: array + title: Lost Access + type: object + title: ImpactAnalysisResponse + MetaBody: + properties: + request_id: + anyOf: + - type: string + - type: 'null' + title: Request Id + limit: + anyOf: + - type: integer + - type: 'null' + title: Limit + next_cursor: + anyOf: + - type: string + - type: 'null' + title: Next Cursor + extra: + additionalProperties: true + type: object + title: Extra + type: object + title: MetaBody + PermissionCreate: + properties: + action: + type: string + title: Action + type: object + required: + - action + title: PermissionCreate + PermissionOut: + properties: + id: + type: integer + title: Id + action: + type: string + title: Action + type: object + required: + - id + - action + title: PermissionOut + PermissionUpdate: + properties: + action: + type: string + title: Action + type: object + required: + - action + title: PermissionUpdate + PlaygroundEvaluateRequest: + properties: + policies: + items: + $ref: '#/components/schemas/PlaygroundPolicy' + type: array + title: Policies + input: + $ref: '#/components/schemas/PlaygroundInput' + type: object + required: + - policies + - input + title: PlaygroundEvaluateRequest + PlaygroundInput: + properties: + user: + additionalProperties: true + type: object + title: User + resource: + additionalProperties: true + type: object + title: Resource + action: + type: string + title: Action + default: '' + context: + additionalProperties: true + type: object + title: Context + type: object + title: PlaygroundInput + PlaygroundPolicy: + properties: + action: + type: string + title: Action + effect: + type: string + title: Effect + default: allow + priority: + type: integer + title: Priority + default: 100 + policy_id: + anyOf: + - type: string + - type: 'null' + title: Policy Id + conditions: + additionalProperties: true + type: object + title: Conditions + type: object + required: + - action + title: PlaygroundPolicy + PolicyCreate: + properties: + action: + type: string + title: Action + effect: + type: string + title: Effect + default: allow + priority: + type: integer + title: Priority + default: 100 + state: + type: string + title: State + default: active + conditions: + additionalProperties: true + type: object + title: Conditions + type: object + required: + - action + title: PolicyCreate + PolicyOut: + properties: + id: + type: integer + title: Id + action: + type: string + title: Action + effect: + type: string + title: Effect + priority: + type: integer + title: Priority + state: + type: string + title: State + default: active + conditions: + additionalProperties: true + type: object + title: Conditions + type: object + required: + - id + - action + - effect + - priority + - conditions + title: PolicyOut + PolicySimulationInput: + properties: + policy_change: + anyOf: + - type: string + - type: 'null' + title: Policy Change + relationship_change: + anyOf: + - additionalProperties: true + type: object + - type: 'null' + title: Relationship Change + role_change: + anyOf: + - additionalProperties: true + type: object + - type: 'null' + title: Role Change + type: object + title: PolicySimulationInput + PolicySimulationRequest: + properties: + simulate: + $ref: '#/components/schemas/PolicySimulationInput' + request: + additionalProperties: true + type: object + title: Request + type: object + title: PolicySimulationRequest + PolicySimulationResponse: + properties: + decision_before: + additionalProperties: true + type: object + title: Decision Before + decision_after: + additionalProperties: true + type: object + title: Decision After + type: object + required: + - decision_before + - decision_after + title: PolicySimulationResponse + RelationshipCreate: + properties: + subject_type: + type: string + title: Subject Type + subject_id: + type: string + title: Subject Id + relation: + type: string + title: Relation + object_type: + type: string + title: Object Type + object_id: + type: string + title: Object Id + type: object + required: + - subject_type + - subject_id + - relation + - object_type + - object_id + title: RelationshipCreate + RelationshipOut: + properties: + subject_type: + type: string + title: Subject Type + subject_id: + type: string + title: Subject Id + relation: + type: string + title: Relation + object_type: + type: string + title: Object Type + object_id: + type: string + title: Object Id + id: + type: integer + title: Id + type: object + required: + - subject_type + - subject_id + - relation + - object_type + - object_id + - id + title: RelationshipOut + RoleCreate: + properties: + name: + type: string + title: Name + type: object + required: + - name + title: RoleCreate + RoleOut: + properties: + id: + type: integer + title: Id + name: + type: string + title: Name + type: object + required: + - id + - name + title: RoleOut + RoleUpdate: + properties: + name: + type: string + title: Name + type: object + required: + - name + title: RoleUpdate + SimulationResponse: + properties: + decision: + type: string + title: Decision + matched_policies: + items: + type: string + type: array + title: Matched Policies + reason: + anyOf: + - type: string + - type: 'null' + title: Reason + policy_id: + anyOf: + - type: string + - type: 'null' + title: Policy Id + explain_trace: + items: + additionalProperties: true + type: object + type: array + title: Explain Trace + failed_conditions: + items: + type: string + type: array + title: Failed Conditions + revision: + anyOf: + - type: integer + - type: 'null' + title: Revision + type: object + required: + - decision + - matched_policies + title: SimulationResponse + SuccessResponse_ACLOut_: + properties: + data: + $ref: '#/components/schemas/ACLOut' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[ACLOut] + SuccessResponse_AccessDecisionResponse_: + properties: + data: + $ref: '#/components/schemas/AccessDecisionResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[AccessDecisionResponse] + SuccessResponse_AdminLoginResponse_: + properties: + data: + $ref: '#/components/schemas/AdminLoginResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[AdminLoginResponse] + SuccessResponse_AuthModelOut_: + properties: + data: + $ref: '#/components/schemas/AuthModelOut' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[AuthModelOut] + SuccessResponse_BatchAccessResponse_: + properties: + data: + $ref: '#/components/schemas/BatchAccessResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[BatchAccessResponse] + SuccessResponse_ImpactAnalysisResponse_: + properties: + data: + $ref: '#/components/schemas/ImpactAnalysisResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[ImpactAnalysisResponse] + SuccessResponse_PermissionOut_: + properties: + data: + $ref: '#/components/schemas/PermissionOut' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[PermissionOut] + SuccessResponse_PolicyOut_: + properties: + data: + $ref: '#/components/schemas/PolicyOut' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[PolicyOut] + SuccessResponse_PolicySimulationResponse_: + properties: + data: + $ref: '#/components/schemas/PolicySimulationResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[PolicySimulationResponse] + SuccessResponse_RelationshipOut_: + properties: + data: + $ref: '#/components/schemas/RelationshipOut' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[RelationshipOut] + SuccessResponse_SimulationResponse_: + properties: + data: + $ref: '#/components/schemas/SimulationResponse' + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[SimulationResponse] + SuccessResponse_dict_str__Any__: + properties: + data: + additionalProperties: true + type: object + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[dict[str, Any]] + SuccessResponse_dict_str__Union_int__str___: + properties: + data: + additionalProperties: + anyOf: + - type: integer + - type: string + type: object + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[dict[str, Union[int, str]]] + SuccessResponse_dict_str__int__: + properties: + data: + additionalProperties: + type: integer + type: object + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[dict[str, int]] + SuccessResponse_dict_str__object__: + properties: + data: + additionalProperties: true + type: object + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[dict[str, object]] + SuccessResponse_dict_str__str__: + properties: + data: + additionalProperties: + type: string + type: object + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[dict[str, str]] + SuccessResponse_list_ACLOut__: + properties: + data: + items: + $ref: '#/components/schemas/ACLOut' + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[ACLOut]] + SuccessResponse_list_AuditRecordOut__: + properties: + data: + items: + $ref: '#/components/schemas/AuditRecordOut' + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[AuditRecordOut]] + SuccessResponse_list_PermissionOut__: + properties: + data: + items: + $ref: '#/components/schemas/PermissionOut' + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[PermissionOut]] + SuccessResponse_list_PolicyOut__: + properties: + data: + items: + $ref: '#/components/schemas/PolicyOut' + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[PolicyOut]] + SuccessResponse_list_RoleOut__: + properties: + data: + items: + $ref: '#/components/schemas/RoleOut' + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[RoleOut]] + SuccessResponse_list_dict_str__str___: + properties: + data: + items: + additionalProperties: + type: string + type: object + type: array + title: Data + meta: + $ref: '#/components/schemas/MetaBody' + error: + type: 'null' + title: Error + type: object + required: + - data + title: SuccessResponse[list[dict[str, str]]] + ValidationError: + properties: + loc: + items: + anyOf: + - type: string + - type: integer + type: array + title: Location + msg: + type: string + title: Message + type: + type: string + title: Error Type + input: + title: Input + ctx: + type: object + title: Context + type: object + required: + - loc + - msg + - type + title: ValidationError + securitySchemes: + HTTPBearer: + type: http + scheme: bearer + APIKeyHeader: + type: apiKey + in: header + name: X-API-Key diff --git a/openapi/openapi.json b/openapi/openapi.json new file mode 100644 index 0000000..691fa8c --- /dev/null +++ b/openapi/openapi.json @@ -0,0 +1,3587 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "KeyNetra", + "version": "0.1.1" + }, + "paths": { + "/health": { + "get": { + "tags": [ + "health" + ], + "summary": "Health", + "operationId": "health_health_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__str__" + } + } + } + } + } + } + }, + "/health/live": { + "get": { + "tags": [ + "health" + ], + "summary": "Liveness", + "operationId": "liveness_health_live_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__str__" + } + } + } + } + } + } + }, + "/health/ready": { + "get": { + "tags": [ + "health" + ], + "summary": "Readiness", + "operationId": "readiness_health_ready_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__object__" + } + } + } + } + } + } + }, + "/check-access": { + "post": { + "tags": [ + "access" + ], + "summary": "Check Access", + "operationId": "check_access_check_access_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "policy_set", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "active", + "title": "Policy Set" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_AccessDecisionResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/simulate": { + "post": { + "tags": [ + "access" + ], + "summary": "Simulate", + "operationId": "simulate_simulate_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccessRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_SimulationResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/check-access-batch": { + "post": { + "tags": [ + "access" + ], + "summary": "Check Access Batch", + "operationId": "check_access_batch_check_access_batch_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "policy_set", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "active", + "title": "Policy Set" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BatchAccessRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_BatchAccessResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/admin/login": { + "post": { + "tags": [ + "auth", + "auth" + ], + "summary": "Admin Login", + "operationId": "admin_login_admin_login_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AdminLoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_AdminLoginResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/policies": { + "get": { + "tags": [ + "management" + ], + "summary": "List Policies", + "operationId": "list_policies_policies_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_PolicyOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "management" + ], + "summary": "Create Policy", + "operationId": "create_policy_policies_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PolicyCreate" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_PolicyOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/policies/{policy_key}": { + "put": { + "tags": [ + "management" + ], + "summary": "Update Policy", + "operationId": "update_policy_policies__policy_key__put", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "policy_key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Policy Key" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PolicyCreate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_PolicyOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "management" + ], + "summary": "Delete Policy", + "operationId": "delete_policy_policies__policy_key__delete", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "policy_key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Policy Key" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__str__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/policies/dsl": { + "post": { + "tags": [ + "management" + ], + "summary": "Create Policy From Dsl", + "operationId": "create_policy_from_dsl_policies_dsl_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "dsl", + "in": "query", + "required": true, + "schema": { + "type": "string", + "title": "Dsl" + } + } + ], + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_PolicyOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/policies/{policy_key}/rollback/{version}": { + "post": { + "tags": [ + "management" + ], + "summary": "Rollback Policy", + "operationId": "rollback_policy_policies__policy_key__rollback__version__post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "policy_key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Policy Key" + } + }, + { + "name": "version", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Version" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__Union_int__str___" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/acl": { + "post": { + "tags": [ + "management" + ], + "summary": "Create Acl Entry", + "operationId": "create_acl_entry_acl_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ACLCreate" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_ACLOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/acl/{resource_type}/{resource_id}": { + "get": { + "tags": [ + "management" + ], + "summary": "List Acl Entries", + "operationId": "list_acl_entries_acl__resource_type___resource_id__get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "resource_type", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Resource Type" + } + }, + { + "name": "resource_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Resource Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_ACLOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/acl/{acl_id}": { + "delete": { + "tags": [ + "management" + ], + "summary": "Delete Acl Entry", + "operationId": "delete_acl_entry_acl__acl_id__delete", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "acl_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Acl Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__int__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/auth-model": { + "get": { + "tags": [ + "management" + ], + "summary": "Get Auth Model", + "operationId": "get_auth_model_auth_model_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_AuthModelOut_" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + }, + "post": { + "tags": [ + "management" + ], + "summary": "Create Auth Model", + "operationId": "create_auth_model_auth_model_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthModelCreate" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_AuthModelOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/simulate-policy": { + "post": { + "tags": [ + "management" + ], + "summary": "Simulate Policy", + "operationId": "simulate_policy_simulate_policy_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PolicySimulationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_PolicySimulationResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/impact-analysis": { + "post": { + "tags": [ + "management" + ], + "summary": "Impact Analysis", + "operationId": "impact_analysis_impact_analysis_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImpactAnalysisRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_ImpactAnalysisResponse_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/roles": { + "get": { + "tags": [ + "management" + ], + "summary": "List Roles", + "operationId": "list_roles_roles_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_RoleOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "management" + ], + "summary": "Create Role", + "operationId": "create_role_roles_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleCreate" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleOut" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/roles/{role_id}": { + "put": { + "tags": [ + "management" + ], + "summary": "Update Role", + "operationId": "update_role_roles__role_id__put", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Role Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoleOut" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "management" + ], + "summary": "Delete Role", + "operationId": "delete_role_roles__role_id__delete", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Role Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__int__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/roles/{role_id}/permissions": { + "get": { + "tags": [ + "management" + ], + "summary": "List Role Permissions", + "operationId": "list_role_permissions_roles__role_id__permissions_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Role Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_PermissionOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/roles/{role_id}/permissions/{permission_id}": { + "post": { + "tags": [ + "management" + ], + "summary": "Add Permission To Role", + "operationId": "add_permission_to_role_roles__role_id__permissions__permission_id__post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Role Id" + } + }, + { + "name": "permission_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Permission Id" + } + } + ], + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_PermissionOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "management" + ], + "summary": "Remove Permission From Role", + "operationId": "remove_permission_from_role_roles__role_id__permissions__permission_id__delete", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "role_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Role Id" + } + }, + { + "name": "permission_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Permission Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__int__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/permissions": { + "get": { + "tags": [ + "management" + ], + "summary": "List Permissions", + "operationId": "list_permissions_permissions_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_PermissionOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "management" + ], + "summary": "Create Permission", + "operationId": "create_permission_permissions_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionCreate" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionOut" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/permissions/{permission_id}": { + "put": { + "tags": [ + "management" + ], + "summary": "Update Permission", + "operationId": "update_permission_permissions__permission_id__put", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "permission_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Permission Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PermissionOut" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "management" + ], + "summary": "Delete Permission", + "operationId": "delete_permission_permissions__permission_id__delete", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "permission_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Permission Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__int__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/permissions/{permission_id}/roles": { + "get": { + "tags": [ + "management" + ], + "summary": "List Permission Roles", + "operationId": "list_permission_roles_permissions__permission_id__roles_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "permission_id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "title": "Permission Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_RoleOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/relationships": { + "get": { + "tags": [ + "management" + ], + "summary": "List Relationships", + "operationId": "list_relationships_relationships_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "subject_type", + "in": "query", + "required": true, + "schema": { + "type": "string", + "title": "Subject Type" + } + }, + { + "name": "subject_id", + "in": "query", + "required": true, + "schema": { + "type": "string", + "title": "Subject Id" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_dict_str__str___" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "management" + ], + "summary": "Create Relationship", + "operationId": "create_relationship_relationships_post", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RelationshipCreate" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_RelationshipOut_" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/audit": { + "get": { + "tags": [ + "management" + ], + "summary": "List Audit Logs", + "operationId": "list_audit_logs_audit_get", + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 50, + "title": "Limit" + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Cursor" + } + }, + { + "name": "user_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "User Id" + } + }, + { + "name": "resource_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Resource Id" + } + }, + { + "name": "decision", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Decision" + } + }, + { + "name": "start_time", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Start Time" + } + }, + { + "name": "end_time", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "End Time" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_list_AuditRecordOut__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/playground/evaluate": { + "post": { + "tags": [ + "playground" + ], + "summary": "Evaluate", + "operationId": "evaluate_playground_evaluate_post", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlaygroundEvaluateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__Any__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + }, + "security": [ + { + "HTTPBearer": [] + }, + { + "APIKeyHeader": [] + } + ] + } + }, + "/dev/sample-data": { + "get": { + "tags": [ + "dev" + ], + "summary": "Get Sample Data", + "operationId": "get_sample_data_dev_sample_data_get", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__object__" + } + } + } + } + } + } + }, + "/dev/sample-data/seed": { + "post": { + "tags": [ + "dev" + ], + "summary": "Seed Sample Data", + "operationId": "seed_sample_data_dev_sample_data_seed_post", + "parameters": [ + { + "name": "reset", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Clear the sample dataset before reseeding it.", + "default": false, + "title": "Reset" + }, + "description": "Clear the sample dataset before reseeding it." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse_dict_str__object__" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "ACLCreate": { + "properties": { + "subject_type": { + "type": "string", + "title": "Subject Type" + }, + "subject_id": { + "type": "string", + "title": "Subject Id" + }, + "resource_type": { + "type": "string", + "title": "Resource Type" + }, + "resource_id": { + "type": "string", + "title": "Resource Id" + }, + "action": { + "type": "string", + "title": "Action" + }, + "effect": { + "type": "string", + "title": "Effect" + } + }, + "type": "object", + "required": [ + "subject_type", + "subject_id", + "resource_type", + "resource_id", + "action", + "effect" + ], + "title": "ACLCreate" + }, + "ACLOut": { + "properties": { + "subject_type": { + "type": "string", + "title": "Subject Type" + }, + "subject_id": { + "type": "string", + "title": "Subject Id" + }, + "resource_type": { + "type": "string", + "title": "Resource Type" + }, + "resource_id": { + "type": "string", + "title": "Resource Id" + }, + "action": { + "type": "string", + "title": "Action" + }, + "effect": { + "type": "string", + "title": "Effect" + }, + "id": { + "type": "integer", + "title": "Id" + }, + "tenant_id": { + "type": "integer", + "title": "Tenant Id" + }, + "created_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Created At" + } + }, + "type": "object", + "required": [ + "subject_type", + "subject_id", + "resource_type", + "resource_id", + "action", + "effect", + "id", + "tenant_id" + ], + "title": "ACLOut" + }, + "AccessDecisionResponse": { + "properties": { + "allowed": { + "type": "boolean", + "title": "Allowed" + }, + "decision": { + "type": "string", + "title": "Decision" + }, + "matched_policies": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Matched Policies" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Reason" + }, + "policy_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Policy Id" + }, + "explain_trace": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array", + "title": "Explain Trace" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "allowed", + "decision" + ], + "title": "AccessDecisionResponse" + }, + "AccessRequest": { + "properties": { + "user": { + "additionalProperties": true, + "type": "object", + "title": "User" + }, + "action": { + "type": "string", + "title": "Action" + }, + "resource": { + "additionalProperties": true, + "type": "object", + "title": "Resource" + }, + "context": { + "additionalProperties": true, + "type": "object", + "title": "Context" + }, + "consistency": { + "type": "string", + "title": "Consistency", + "default": "eventual" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "AccessRequest", + "description": "Explicit authorization request passed through the API boundary." + }, + "AdminLoginRequest": { + "properties": { + "username": { + "type": "string", + "title": "Username" + }, + "password": { + "type": "string", + "title": "Password" + } + }, + "type": "object", + "required": [ + "username", + "password" + ], + "title": "AdminLoginRequest" + }, + "AdminLoginResponse": { + "properties": { + "access_token": { + "type": "string", + "title": "Access Token" + }, + "token_type": { + "type": "string", + "title": "Token Type", + "default": "bearer" + }, + "expires_in": { + "type": "integer", + "title": "Expires In" + }, + "role": { + "type": "string", + "title": "Role", + "default": "admin" + }, + "tenant_key": { + "type": "string", + "title": "Tenant Key" + } + }, + "type": "object", + "required": [ + "access_token", + "expires_in", + "tenant_key" + ], + "title": "AdminLoginResponse" + }, + "AuditRecordOut": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "principal_type": { + "type": "string", + "title": "Principal Type" + }, + "principal_id": { + "type": "string", + "title": "Principal Id" + }, + "correlation_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Correlation Id" + }, + "user": { + "additionalProperties": true, + "type": "object", + "title": "User" + }, + "action": { + "type": "string", + "title": "Action" + }, + "resource": { + "additionalProperties": true, + "type": "object", + "title": "Resource" + }, + "decision": { + "type": "string", + "title": "Decision" + }, + "matched_policies": { + "items": {}, + "type": "array", + "title": "Matched Policies" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Reason" + }, + "evaluated_rules": { + "items": {}, + "type": "array", + "title": "Evaluated Rules" + }, + "failed_conditions": { + "items": {}, + "type": "array", + "title": "Failed Conditions" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + } + }, + "type": "object", + "required": [ + "id", + "principal_type", + "principal_id", + "user", + "action", + "resource", + "decision", + "matched_policies", + "evaluated_rules", + "failed_conditions", + "created_at" + ], + "title": "AuditRecordOut" + }, + "AuthModelCreate": { + "properties": { + "schema": { + "type": "string", + "title": "Schema" + } + }, + "type": "object", + "required": [ + "schema" + ], + "title": "AuthModelCreate" + }, + "AuthModelOut": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "tenant_id": { + "type": "integer", + "title": "Tenant Id" + }, + "schema": { + "type": "string", + "title": "Schema" + }, + "parsed": { + "additionalProperties": true, + "type": "object", + "title": "Parsed" + }, + "compiled": { + "additionalProperties": true, + "type": "object", + "title": "Compiled" + } + }, + "type": "object", + "required": [ + "id", + "tenant_id", + "schema", + "parsed", + "compiled" + ], + "title": "AuthModelOut" + }, + "BatchAccessItem": { + "properties": { + "action": { + "type": "string", + "title": "Action" + }, + "resource": { + "additionalProperties": true, + "type": "object", + "title": "Resource" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "BatchAccessItem" + }, + "BatchAccessRequest": { + "properties": { + "user": { + "additionalProperties": true, + "type": "object", + "title": "User" + }, + "items": { + "items": { + "$ref": "#/components/schemas/BatchAccessItem" + }, + "type": "array", + "title": "Items" + }, + "consistency": { + "type": "string", + "title": "Consistency", + "default": "eventual" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "items" + ], + "title": "BatchAccessRequest" + }, + "BatchAccessResponse": { + "properties": { + "results": { + "items": { + "$ref": "#/components/schemas/BatchAccessResult" + }, + "type": "array", + "title": "Results" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "results" + ], + "title": "BatchAccessResponse" + }, + "BatchAccessResult": { + "properties": { + "action": { + "type": "string", + "title": "Action" + }, + "allowed": { + "type": "boolean", + "title": "Allowed" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "action", + "allowed" + ], + "title": "BatchAccessResult" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "type": "array", + "title": "Detail" + } + }, + "type": "object", + "title": "HTTPValidationError" + }, + "ImpactAnalysisRequest": { + "properties": { + "policy_change": { + "type": "string", + "title": "Policy Change" + } + }, + "type": "object", + "required": [ + "policy_change" + ], + "title": "ImpactAnalysisRequest" + }, + "ImpactAnalysisResponse": { + "properties": { + "gained_access": { + "items": { + "type": "integer" + }, + "type": "array", + "title": "Gained Access" + }, + "lost_access": { + "items": { + "type": "integer" + }, + "type": "array", + "title": "Lost Access" + } + }, + "type": "object", + "title": "ImpactAnalysisResponse" + }, + "MetaBody": { + "properties": { + "request_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Request Id" + }, + "limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Limit" + }, + "next_cursor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Next Cursor" + }, + "extra": { + "additionalProperties": true, + "type": "object", + "title": "Extra" + } + }, + "type": "object", + "title": "MetaBody" + }, + "PermissionCreate": { + "properties": { + "action": { + "type": "string", + "title": "Action" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "PermissionCreate" + }, + "PermissionOut": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "action": { + "type": "string", + "title": "Action" + } + }, + "type": "object", + "required": [ + "id", + "action" + ], + "title": "PermissionOut" + }, + "PermissionUpdate": { + "properties": { + "action": { + "type": "string", + "title": "Action" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "PermissionUpdate" + }, + "PlaygroundEvaluateRequest": { + "properties": { + "policies": { + "items": { + "$ref": "#/components/schemas/PlaygroundPolicy" + }, + "type": "array", + "title": "Policies" + }, + "input": { + "$ref": "#/components/schemas/PlaygroundInput" + } + }, + "type": "object", + "required": [ + "policies", + "input" + ], + "title": "PlaygroundEvaluateRequest" + }, + "PlaygroundInput": { + "properties": { + "user": { + "additionalProperties": true, + "type": "object", + "title": "User" + }, + "resource": { + "additionalProperties": true, + "type": "object", + "title": "Resource" + }, + "action": { + "type": "string", + "title": "Action", + "default": "" + }, + "context": { + "additionalProperties": true, + "type": "object", + "title": "Context" + } + }, + "type": "object", + "title": "PlaygroundInput" + }, + "PlaygroundPolicy": { + "properties": { + "action": { + "type": "string", + "title": "Action" + }, + "effect": { + "type": "string", + "title": "Effect", + "default": "allow" + }, + "priority": { + "type": "integer", + "title": "Priority", + "default": 100 + }, + "policy_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Policy Id" + }, + "conditions": { + "additionalProperties": true, + "type": "object", + "title": "Conditions" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "PlaygroundPolicy" + }, + "PolicyCreate": { + "properties": { + "action": { + "type": "string", + "title": "Action" + }, + "effect": { + "type": "string", + "title": "Effect", + "default": "allow" + }, + "priority": { + "type": "integer", + "title": "Priority", + "default": 100 + }, + "state": { + "type": "string", + "title": "State", + "default": "active" + }, + "conditions": { + "additionalProperties": true, + "type": "object", + "title": "Conditions" + } + }, + "type": "object", + "required": [ + "action" + ], + "title": "PolicyCreate" + }, + "PolicyOut": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "action": { + "type": "string", + "title": "Action" + }, + "effect": { + "type": "string", + "title": "Effect" + }, + "priority": { + "type": "integer", + "title": "Priority" + }, + "state": { + "type": "string", + "title": "State", + "default": "active" + }, + "conditions": { + "additionalProperties": true, + "type": "object", + "title": "Conditions" + } + }, + "type": "object", + "required": [ + "id", + "action", + "effect", + "priority", + "conditions" + ], + "title": "PolicyOut" + }, + "PolicySimulationInput": { + "properties": { + "policy_change": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Policy Change" + }, + "relationship_change": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Relationship Change" + }, + "role_change": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Role Change" + } + }, + "type": "object", + "title": "PolicySimulationInput" + }, + "PolicySimulationRequest": { + "properties": { + "simulate": { + "$ref": "#/components/schemas/PolicySimulationInput" + }, + "request": { + "additionalProperties": true, + "type": "object", + "title": "Request" + } + }, + "type": "object", + "title": "PolicySimulationRequest" + }, + "PolicySimulationResponse": { + "properties": { + "decision_before": { + "additionalProperties": true, + "type": "object", + "title": "Decision Before" + }, + "decision_after": { + "additionalProperties": true, + "type": "object", + "title": "Decision After" + } + }, + "type": "object", + "required": [ + "decision_before", + "decision_after" + ], + "title": "PolicySimulationResponse" + }, + "RelationshipCreate": { + "properties": { + "subject_type": { + "type": "string", + "title": "Subject Type" + }, + "subject_id": { + "type": "string", + "title": "Subject Id" + }, + "relation": { + "type": "string", + "title": "Relation" + }, + "object_type": { + "type": "string", + "title": "Object Type" + }, + "object_id": { + "type": "string", + "title": "Object Id" + } + }, + "type": "object", + "required": [ + "subject_type", + "subject_id", + "relation", + "object_type", + "object_id" + ], + "title": "RelationshipCreate" + }, + "RelationshipOut": { + "properties": { + "subject_type": { + "type": "string", + "title": "Subject Type" + }, + "subject_id": { + "type": "string", + "title": "Subject Id" + }, + "relation": { + "type": "string", + "title": "Relation" + }, + "object_type": { + "type": "string", + "title": "Object Type" + }, + "object_id": { + "type": "string", + "title": "Object Id" + }, + "id": { + "type": "integer", + "title": "Id" + } + }, + "type": "object", + "required": [ + "subject_type", + "subject_id", + "relation", + "object_type", + "object_id", + "id" + ], + "title": "RelationshipOut" + }, + "RoleCreate": { + "properties": { + "name": { + "type": "string", + "title": "Name" + } + }, + "type": "object", + "required": [ + "name" + ], + "title": "RoleCreate" + }, + "RoleOut": { + "properties": { + "id": { + "type": "integer", + "title": "Id" + }, + "name": { + "type": "string", + "title": "Name" + } + }, + "type": "object", + "required": [ + "id", + "name" + ], + "title": "RoleOut" + }, + "RoleUpdate": { + "properties": { + "name": { + "type": "string", + "title": "Name" + } + }, + "type": "object", + "required": [ + "name" + ], + "title": "RoleUpdate" + }, + "SimulationResponse": { + "properties": { + "decision": { + "type": "string", + "title": "Decision" + }, + "matched_policies": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Matched Policies" + }, + "reason": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Reason" + }, + "policy_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Policy Id" + }, + "explain_trace": { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array", + "title": "Explain Trace" + }, + "failed_conditions": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Failed Conditions" + }, + "revision": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Revision" + } + }, + "type": "object", + "required": [ + "decision", + "matched_policies" + ], + "title": "SimulationResponse" + }, + "SuccessResponse_ACLOut_": { + "properties": { + "data": { + "$ref": "#/components/schemas/ACLOut" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[ACLOut]" + }, + "SuccessResponse_AccessDecisionResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/AccessDecisionResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[AccessDecisionResponse]" + }, + "SuccessResponse_AdminLoginResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/AdminLoginResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[AdminLoginResponse]" + }, + "SuccessResponse_AuthModelOut_": { + "properties": { + "data": { + "$ref": "#/components/schemas/AuthModelOut" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[AuthModelOut]" + }, + "SuccessResponse_BatchAccessResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/BatchAccessResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[BatchAccessResponse]" + }, + "SuccessResponse_ImpactAnalysisResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/ImpactAnalysisResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[ImpactAnalysisResponse]" + }, + "SuccessResponse_PermissionOut_": { + "properties": { + "data": { + "$ref": "#/components/schemas/PermissionOut" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[PermissionOut]" + }, + "SuccessResponse_PolicyOut_": { + "properties": { + "data": { + "$ref": "#/components/schemas/PolicyOut" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[PolicyOut]" + }, + "SuccessResponse_PolicySimulationResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/PolicySimulationResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[PolicySimulationResponse]" + }, + "SuccessResponse_RelationshipOut_": { + "properties": { + "data": { + "$ref": "#/components/schemas/RelationshipOut" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[RelationshipOut]" + }, + "SuccessResponse_SimulationResponse_": { + "properties": { + "data": { + "$ref": "#/components/schemas/SimulationResponse" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[SimulationResponse]" + }, + "SuccessResponse_dict_str__Any__": { + "properties": { + "data": { + "additionalProperties": true, + "type": "object", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[dict[str, Any]]" + }, + "SuccessResponse_dict_str__Union_int__str___": { + "properties": { + "data": { + "additionalProperties": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "type": "object", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[dict[str, Union[int, str]]]" + }, + "SuccessResponse_dict_str__int__": { + "properties": { + "data": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[dict[str, int]]" + }, + "SuccessResponse_dict_str__object__": { + "properties": { + "data": { + "additionalProperties": true, + "type": "object", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[dict[str, object]]" + }, + "SuccessResponse_dict_str__str__": { + "properties": { + "data": { + "additionalProperties": { + "type": "string" + }, + "type": "object", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[dict[str, str]]" + }, + "SuccessResponse_list_ACLOut__": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/ACLOut" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[ACLOut]]" + }, + "SuccessResponse_list_AuditRecordOut__": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/AuditRecordOut" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[AuditRecordOut]]" + }, + "SuccessResponse_list_PermissionOut__": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/PermissionOut" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[PermissionOut]]" + }, + "SuccessResponse_list_PolicyOut__": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/PolicyOut" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[PolicyOut]]" + }, + "SuccessResponse_list_RoleOut__": { + "properties": { + "data": { + "items": { + "$ref": "#/components/schemas/RoleOut" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[RoleOut]]" + }, + "SuccessResponse_list_dict_str__str___": { + "properties": { + "data": { + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array", + "title": "Data" + }, + "meta": { + "$ref": "#/components/schemas/MetaBody" + }, + "error": { + "type": "null", + "title": "Error" + } + }, + "type": "object", + "required": [ + "data" + ], + "title": "SuccessResponse[list[dict[str, str]]]" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "type": "array", + "title": "Location" + }, + "msg": { + "type": "string", + "title": "Message" + }, + "type": { + "type": "string", + "title": "Error Type" + }, + "input": { + "title": "Input" + }, + "ctx": { + "type": "object", + "title": "Context" + } + }, + "type": "object", + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError" + } + }, + "securitySchemes": { + "HTTPBearer": { + "type": "http", + "scheme": "bearer" + }, + "APIKeyHeader": { + "type": "apiKey", + "in": "header", + "name": "X-API-Key" + } + } + } +} \ No newline at end of file diff --git a/openapitools.json b/openapitools.json new file mode 100644 index 0000000..91d9c43 --- /dev/null +++ b/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.21.0" + } +} diff --git a/scripts/generate-all.sh b/scripts/generate-all.sh new file mode 100755 index 0000000..450cb8f --- /dev/null +++ b/scripts/generate-all.sh @@ -0,0 +1,405 @@ +#!/usr/bin/env bash +set -euo pipefail + +# --- Configuration --- +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SPEC_FILE="${ROOT_DIR}/openapi/keynetra.yaml" +SDK_VERSION="${SDK_VERSION:-0.1.1}" + +# --- Colors & Emojis --- +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +CHECK="โœ…" +ROCKET="๐Ÿš€" +GEAR="โš™๏ธ" +BUILD="๐Ÿ› ๏ธ" +PACKAGE="๐Ÿ“ฆ" + +# --- Functions --- +log_info() { echo -e "${BLUE}${GEAR} [INFO]${NC} $1"; } +log_success() { echo -e "${GREEN}${CHECK} [SUCCESS]${NC} $1"; } +log_step() { echo -e "${CYAN}${BUILD} [STEP]${NC} $1"; } +log_warn() { echo -e "${YELLOW}โš ๏ธ [WARN]${NC} $1"; } +log_error() { echo -e "${RED}โŒ [ERROR]${NC} $1"; } + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + log_error "missing required command: $1" >&2 + exit 1 + fi +} + +install_generator() { + if command -v openapi-generator-cli >/dev/null 2>&1; then + log_info "OpenAPI Generator already installed." + # Ensure a version is selected and downloaded to avoid parallel download race conditions + openapi-generator-cli version >/dev/null 2>&1 + return + fi + + log_step "Installing OpenAPI Generator..." + require_cmd npm + npm install -g @openapitools/openapi-generator-cli + # Pre-download the jar to avoid parallel race conditions + openapi-generator-cli version >/dev/null 2>&1 +} + +generate_sdk() { + local generator="$1" + local output_dir="$2" + local config_file="$3" + local name="${4:-$generator}" + local log_file="${ROOT_DIR}/sdks/gen-${name}.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_python() { + local generator="python" + local output_dir="${ROOT_DIR}/sdks/python" + local config_file="${ROOT_DIR}/templates/python-config.yaml" + local name="Python" + local log_file="${ROOT_DIR}/sdks/gen-Python.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=Any \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_go() { + local generator="go" + local output_dir="${ROOT_DIR}/sdks/go" + local config_file="${ROOT_DIR}/templates/go-config.yaml" + local name="Go" + local log_file="${ROOT_DIR}/sdks/gen-Go.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + # Go-specific mappings and flags to handle anyOf and untyped fields + # Using interface{} instead of any to avoid composite literal issues + # We use disallowAdditionalPropertiesIfNotPresent=false to avoid syntax errors with unexpected fields + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ +--type-mappings=null=interface{},object=map[string]interface{},Any=interface{} \ + --additional-properties=disallowAdditionalPropertiesIfNotPresent=false \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_kotlin() { + local generator="kotlin" + local output_dir="${ROOT_DIR}/sdks/kotlin" + local config_file="${ROOT_DIR}/templates/kotlin-config.yaml" + local name="Kotlin" + local log_file="${ROOT_DIR}/sdks/gen-Kotlin.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + # Kotlin-specific mappings to handle serialization of Any types + # Using kotlinx.serialization.json.JsonElement for better compatibility with KMP + # We also add import mappings to ensure the generator knows where JsonElement comes from + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=kotlinx.serialization.json.JsonElement,Any=kotlinx.serialization.json.JsonElement,object=kotlinx.serialization.json.JsonElement,JsonElement=kotlinx.serialization.json.JsonElement \ + --import-mappings=JsonElement=kotlinx.serialization.json.JsonElement \ +--additional-properties=enumPropertyNaming=original,library=multiplatform,serializationLibrary=kotlinx_serialization \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_ruby() { + local generator="ruby" + local output_dir="${ROOT_DIR}/sdks/ruby" + local config_file="${ROOT_DIR}/templates/ruby-config.yaml" + local name="Ruby" + local log_file="${ROOT_DIR}/sdks/gen-Ruby.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=Object \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_typescript() { + local generator="typescript-fetch" + local output_dir="${ROOT_DIR}/sdks/typescript" + local config_file="${ROOT_DIR}/templates/typescript-config.yaml" + local name="TypeScript" + local log_file="${ROOT_DIR}/sdks/gen-TypeScript.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=any \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_rust() { + local generator="rust" + local output_dir="${ROOT_DIR}/sdks/rust" + local config_file="${ROOT_DIR}/templates/rust-config.yaml" + local name="Rust" + local log_file="${ROOT_DIR}/sdks/gen-Rust.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + # Rust-specific mappings to handle 'null' types + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=serde_json::Value,Null=serde_json::Value \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_java() { + local generator="java" + local output_dir="${ROOT_DIR}/sdks/java" + local config_file="${ROOT_DIR}/templates/java-config.yaml" + local name="Java" + local log_file="${ROOT_DIR}/sdks/gen-Java.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=Object \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_csharp() { + local generator="csharp" + local output_dir="${ROOT_DIR}/sdks/csharp" + local config_file="${ROOT_DIR}/templates/csharp-config.yaml" + local name="C#" + local log_file="${ROOT_DIR}/sdks/gen-CSharp.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --additional-properties=packageCompany=KeyNetra,packageAuthors=KeyNetra,packageProjectUrl=https://github.com/keynetra/keynetra-client-csharp,packageLicenseExpression=Apache-2.0 \ + --type-mappings=null=object \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_php() { + local generator="php" + local output_dir="${ROOT_DIR}/sdks/php" + local config_file="${ROOT_DIR}/templates/php-config.yaml" + local name="PHP" + local log_file="${ROOT_DIR}/sdks/gen-PHP.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=mixed \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +generate_sdk_swift() { + local generator="swift6" + local output_dir="${ROOT_DIR}/sdks/swift" + local config_file="${ROOT_DIR}/templates/swift-config.yaml" + local name="Swift" + local log_file="${ROOT_DIR}/sdks/gen-Swift.log" + + log_step "Generating ${name} SDK..." + rm -rf "${output_dir}" + mkdir -p "${output_dir}" + + if openapi-generator-cli generate \ + -i "${SPEC_FILE}" \ + -g "${generator}" \ + -o "${output_dir}" \ + -c "${config_file}" \ + --type-mappings=null=Any \ + --skip-validate-spec > "${log_file}" 2>&1; then + log_success "${name} SDK generated successfully." + rm -f "${log_file}" + else + log_error "Failed to generate ${name} SDK. See details below:" + cat "${log_file}" + rm -f "${log_file}" + return 1 + fi +} + +# --- Execution --- +echo -e "${YELLOW}${ROCKET} Starting KeyNetra SDK Generation v${SDK_VERSION}${NC}" + +install_generator + +# Generate in parallel +log_info "Generating SDKs in parallel..." + +FAIL=0 + +(generate_sdk_python) || FAIL=1 & +(generate_sdk_typescript) || FAIL=1 & +(generate_sdk_go) || FAIL=1 & +(generate_sdk_java) || FAIL=1 & +(generate_sdk_rust) || FAIL=1 & +(generate_sdk_csharp) || FAIL=1 & +(generate_sdk_php) || FAIL=1 & +(generate_sdk_ruby) || FAIL=1 & +# (generate_sdk_kotlin) || FAIL=1 & +(generate_sdk_swift) || FAIL=1 & + +# Wait for all background jobs to finish +for job in $(jobs -p); do + wait "$job" || FAIL=1 +done + +if [ "$FAIL" -ne 0 ]; then + log_error "One or more SDK generation tasks failed." + exit 1 +fi + +log_step "Preparing packages..." +SDK_VERSION="${SDK_VERSION}" "${ROOT_DIR}/scripts/prepare-packages.sh" + +log_success "All KeyNetra SDKs generated for version ${SDK_VERSION}." +echo -e "${GREEN}${PACKAGE} Ready for distribution!${NC}" diff --git a/scripts/openapitools.json b/scripts/openapitools.json new file mode 100644 index 0000000..91d9c43 --- /dev/null +++ b/scripts/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.21.0" + } +} diff --git a/scripts/prepare-packages.sh b/scripts/prepare-packages.sh new file mode 100755 index 0000000..0ad42e1 --- /dev/null +++ b/scripts/prepare-packages.sh @@ -0,0 +1,723 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SDK_VERSION="${SDK_VERSION:-0.1.1}" + +# --- Colors & Emojis --- +GREEN='\033[0;32m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color +CHECK="โœ…" +BUILD="๐Ÿ› ๏ธ" + +log_step() { echo -e "${CYAN}${BUILD} [PREPARE]${NC} $1"; } +log_success() { echo -e "${GREEN}${CHECK} [SUCCESS]${NC} $1"; } + +# Professional README template for SDKs +generate_readme() { + local lang_name="$1" + local pkg_name="$2" + local install_cmd="$3" + local usage_example="$4" + local repo_url="$5" + local docs_url="${6:-https://docs.keynetra.com}" + local extra_info="${7:-}" + local lang_lower=$(echo "$lang_name" | tr '[:upper:]' '[:lower:]') + + cat < "${ROOT_DIR}/sdks/python/README.md" + + cat > "${ROOT_DIR}/sdks/python/pyproject.toml" <=68", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "keynetra-client" +version = "${SDK_VERSION}" +description = "Official Python Client SDK for the KeyNetra authorization platform." +readme = "README.md" +requires-python = ">=3.11" +license = { text = "Apache-2.0" } +authors = [{ name = "Sainath.Sapa", email = "info.djsai@gmail.com" }] +dependencies = [ + "urllib3>=2.1.0", + "python-dateutil>=2.8.2", + "pydantic>=2.11", + "typing-extensions>=4.7.1", +] + +[project.urls] +Homepage = "${repo_url}" +Repository = "${repo_url}" +Issues = "${repo_url}/issues" + +[tool.setuptools.packages.find] +include = ["keynetra_client*"] +EOF + + cat > "${ROOT_DIR}/sdks/python/keynetra_client/__init__.py" <<'EOF' +from .client import KeyNetraClient + +__all__ = ["KeyNetraClient"] +EOF + + cat > "${ROOT_DIR}/sdks/python/keynetra_client/client.py" <<'EOF' +from __future__ import annotations + +from keynetra_client.api_client import ApiClient +from keynetra_client.configuration import Configuration +from keynetra_client.api.access_api import AccessApi +from keynetra_client.api.auth_api import AuthApi +from keynetra_client.api.dev_api import DevApi +from keynetra_client.api.health_api import HealthApi +from keynetra_client.api.management_api import ManagementApi +from keynetra_client.api.playground_api import PlaygroundApi + + +class KeyNetraClient: + def __init__(self, base_url: str, api_key: str) -> None: + configuration = Configuration(host=base_url) + configuration.api_key["APIKeyHeader"] = api_key + configuration.access_token = api_key + self.api_client = ApiClient(configuration=configuration) + + self.access = AccessApi(api_client=self.api_client) + self.auth = AuthApi(api_client=self.api_client) + self.dev = DevApi(api_client=self.api_client) + self.health = HealthApi(api_client=self.api_client) + self.management = ManagementApi(api_client=self.api_client) + self.playground = PlaygroundApi(api_client=self.api_client) +EOF +} + +prepare_typescript() { + log_step "TypeScript" + mkdir -p "${ROOT_DIR}/sdks/typescript/src" + local repo_url="https://github.com/keynetra/keynetra-client-typescript" + local docs_url="https://docs.keynetra.com/sdks/typescript" + + generate_readme "TypeScript" "@keynetra/client" "npm install @keynetra/client" "import { KeyNetraClient } from \"@keynetra/client\"; + +const client = new KeyNetraClient({ + baseUrl: \"http://localhost:8080\", + apiKey: \"YOUR_API_KEY\" +}); + +// Perform an access check +const decision = await client.access.checkAccess({ + subject: \"user:123\", + action: \"read\", + resource: \"document:456\" +});" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/typescript/README.md" + + cat > "${ROOT_DIR}/sdks/typescript/package.json" <", + "repository": { + "type": "git", + "url": "git+${repo_url}.git" + }, + "homepage": "${repo_url}", + "scripts": { + "build": "tsc -p tsconfig.json" + }, + "devDependencies": { + "typescript": "^5.0.0" + } +} +EOF + + cat > "${ROOT_DIR}/sdks/typescript/tsconfig.json" <<'EOF' +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "declaration": true, + "outDir": "dist", + "rootDir": "src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts"] +} +EOF + + cat > "${ROOT_DIR}/sdks/typescript/src/keynetra-client.ts" <<'EOF' +import { + Configuration, + AccessApi, + AuthApi, + DevApi, + HealthApi, + ManagementApi, + PlaygroundApi +} from "./index"; + +export class KeyNetraClient { + public readonly access: AccessApi; + public readonly auth: AuthApi; + public readonly dev: DevApi; + public readonly health: HealthApi; + public readonly management: ManagementApi; + public readonly playground: PlaygroundApi; + + constructor(options: { baseUrl: string, apiKey: string }) { + const configuration = new Configuration({ + basePath: options.baseUrl, + headers: { + "X-API-Key": options.apiKey, + Authorization: `Bearer ${options.apiKey}`, + }, + }); + + this.access = new AccessApi(configuration); + this.auth = new AuthApi(configuration); + this.dev = new DevApi(configuration); + this.health = new HealthApi(configuration); + this.management = new ManagementApi(configuration); + this.playground = new PlaygroundApi(configuration); + } +} +EOF + + # Ensure the wrapper is exported in the main index + # We use a temporary file to avoid issues with concurrent reads/writes + if [ -f "${ROOT_DIR}/sdks/typescript/src/index.ts" ]; then + if ! grep -q "keynetra-client" "${ROOT_DIR}/sdks/typescript/src/index.ts"; then + echo "export * from './keynetra-client';" >> "${ROOT_DIR}/sdks/typescript/src/index.ts" + fi + fi +} + +prepare_go() { + log_step "Go" + local repo_url="https://github.com/keynetra/keynetra-client-go" + local docs_url="https://docs.keynetra.com/sdks/go" + generate_readme "Go" "keynetra-client-go" "go get github.com/keynetra/keynetra-client-go" "import \"github.com/keynetra/keynetra-client-go\" + +client := keynetra.NewKeyNetraClient( + \"http://localhost:8080\", + \"YOUR_API_KEY\", +) + +// Perform an access check +decision, _, err := client.Access.CheckAccess(context.Background()). + AccessRequest(keynetra.AccessRequest{ + Subject: \"user:123\", + Action: \"read\", + Resource: \"document:456\", + }).Execute()" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/go/README.md" + + cat > "${ROOT_DIR}/sdks/go/keynetra_client.go" <<'EOF' +package keynetra + +type KeyNetraClient struct { + Access any + Auth any + Dev any + Health any + Management any + Playground any + client *APIClient +} + +func NewKeyNetraClient(baseURL string, apiKey string) *KeyNetraClient { + cfg := NewConfiguration() + cfg.Servers = ServerConfigurations{{URL: baseURL}} + cfg.DefaultHeader["X-API-Key"] = apiKey + cfg.DefaultHeader["Authorization"] = "Bearer " + apiKey + + client := NewAPIClient(cfg) + + return &KeyNetraClient{ + Access: client.AccessAPI, + Auth: client.AuthAPI, + Dev: client.DevAPI, + Health: client.HealthAPI, + Management: client.ManagementAPI, + Playground: client.PlaygroundAPI, + client: client, + } +} +EOF +} + +prepare_java() { + log_step "Java" + mkdir -p "${ROOT_DIR}/sdks/java/src/main/java/io/keynetra/client" + local repo_url="https://github.com/keynetra/keynetra-client-java" + local docs_url="https://docs.keynetra.com/sdks/java" + + # Ensure gradlew is executable + if [ -f "${ROOT_DIR}/sdks/java/gradlew" ]; then + chmod +x "${ROOT_DIR}/sdks/java/gradlew" + fi + + generate_readme "Java" "keynetra-client" " + io.keynetra + keynetra-client + ${SDK_VERSION} +" "import io.keynetra.client.KeyNetraClient; +import io.keynetra.client.model.AccessRequest; + +KeyNetraClient client = new KeyNetraClient( + \"http://localhost:8080\", + \"YOUR_API_KEY\" +); + +// Perform an access check +var decision = client.getAccess().checkAccess( + new AccessRequest() + .subject(\"user:123\") + .action(\"read\") + .resource(\"document:456\") +);" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/java/README.md" + + cat > "${ROOT_DIR}/sdks/java/src/main/java/io/keynetra/client/KeyNetraClient.java" <<'EOF' +package io.keynetra.client; + +import io.keynetra.client.api.*; + +public class KeyNetraClient { + private final ApiClient apiClient; + private final AccessApi access; + private final AuthApi auth; + private final DevApi dev; + private final HealthApi health; + private final ManagementApi management; + private final PlaygroundApi playground; + + public KeyNetraClient(String baseUrl, String apiKey) { + this.apiClient = new ApiClient(); + this.apiClient.setBasePath(baseUrl); + this.apiClient.addDefaultHeader("X-API-Key", apiKey); + this.apiClient.addDefaultHeader("Authorization", "Bearer " + apiKey); + + this.access = new AccessApi(this.apiClient); + this.auth = new AuthApi(this.apiClient); + this.dev = new DevApi(this.apiClient); + this.health = new HealthApi(this.apiClient); + this.management = new ManagementApi(this.apiClient); + this.playground = new PlaygroundApi(this.apiClient); + } + + public AccessApi getAccess() { return access; } + public AuthApi getAuth() { return auth; } + public DevApi getDev() { return dev; } + public HealthApi getHealth() { return health; } + public ManagementApi getManagement() { return management; } + public PlaygroundApi getPlayground() { return playground; } +} +EOF +} + +prepare_rust() { + log_step "Rust" + mkdir -p "${ROOT_DIR}/sdks/rust/src" + local repo_url="https://github.com/keynetra/keynetra-client-rust" + local docs_url="https://docs.keynetra.com/sdks/rust" + + generate_readme "Rust" "keynetra-client" "cargo add keynetra-client" "use keynetra_client::keynetra_client::KeyNetraClient; + +let client = KeyNetraClient::new( + \"http://localhost:8080\", + \"YOUR_API_KEY\" +); + +// Perform an access check +let decision = client.access() + .check_access(...) + .await?;" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/rust/README.md" + + # Fix Cargo.toml metadata + if [ -f "${ROOT_DIR}/sdks/rust/Cargo.toml" ]; then + perl -i -pe "s/description = .*/description = \"Official Rust Client SDK for the KeyNetra authorization platform.\"/g" "${ROOT_DIR}/sdks/rust/Cargo.toml" + perl -i -pe "s/license = .*/license = \"Apache-2.0\"/g" "${ROOT_DIR}/sdks/rust/Cargo.toml" + perl -i -pe "s/authors = .*/authors = [\"KeyNetra \"]/g" "${ROOT_DIR}/sdks/rust/Cargo.toml" + # Add readme field if missing + if ! grep -q "readme =" "${ROOT_DIR}/sdks/rust/Cargo.toml"; then + perl -i -pe 's/^\[package\]/\[package\]\nreadme = \"README.md\"/' "${ROOT_DIR}/sdks/rust/Cargo.toml" + fi + fi + + cat > "${ROOT_DIR}/sdks/rust/src/keynetra_client.rs" <<'EOF' +use crate::apis::configuration::Configuration; +use crate::apis::access_api::AccessApi; +use crate::apis::auth_api::AuthApi; +use crate::apis::dev_api::DevApi; +use crate::apis::health_api::HealthApi; +use crate::apis::management_api::ManagementApi; +use crate::apis::playground_api::PlaygroundApi; + +pub struct KeyNetraClient { + pub configuration: Configuration, +} + +impl KeyNetraClient { + pub fn new(base_url: &str, api_key: &str) -> Self { + let mut configuration = Configuration::new(); + configuration.base_path = base_url.to_owned(); + configuration.api_key = Some(crate::apis::configuration::ApiKey { + prefix: None, + key: api_key.to_owned(), + }); + + Self { configuration } + } + + pub fn access(&self) -> AccessApi { AccessApi::new(self.configuration.clone()) } + pub fn auth(&self) -> AuthApi { AuthApi::new(self.configuration.clone()) } + pub fn dev(&self) -> DevApi { DevApi::new(self.configuration.clone()) } + pub fn health(&self) -> HealthApi { HealthApi::new(self.configuration.clone()) } + pub fn management(&self) -> ManagementApi { ManagementApi::new(self.configuration.clone()) } + pub fn playground(&self) -> PlaygroundApi { PlaygroundApi::new(self.configuration.clone()) } +} +EOF +} + +prepare_csharp() { + log_step "C#" + mkdir -p "${ROOT_DIR}/sdks/csharp/src/KeyNetra.Client" + local repo_url="https://github.com/keynetra/keynetra-client-csharp" + local docs_url="https://docs.keynetra.com/sdks/csharp" + + generate_readme "C#" "KeyNetra.Client" "dotnet add package KeyNetra.Client" "using KeyNetra.Client; + +var client = new KeyNetraClient( + \"http://localhost:8080\", + \"YOUR_API_KEY\" +); + +// Perform an access check +var decision = await client.Access.CheckAccessAsync(new AccessRequest { + Subject = \"user:123\", + Action = \"read\", + Resource = \"document:456\" +});" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/csharp/README.md" + + perl -0i -pe 's@\[\!\[Version\]\(([^)]+)\)\]\(\)@[![Version]($1)]('"${repo_url}"'/releases)@g' "${ROOT_DIR}/sdks/csharp/README.md" + + # Copy README for NuGet packaging + cp "${ROOT_DIR}/sdks/csharp/README.md" "${ROOT_DIR}/sdks/csharp/src/KeyNetra.Client/README.md" + + # --------------------------------------------------------- +# Fix .csproj metadata (NuGet-safe) +# --------------------------------------------------------- + +CSHARP_PROJ="${ROOT_DIR}/sdks/csharp/src/KeyNetra.Client/KeyNetra.Client.csproj" + +if [ -f "$CSHARP_PROJ" ]; then + + echo "Fixing CSharp package metadata..." + + # Repository URL (must NOT contain .git) + if grep -q "" "$CSHARP_PROJ"; then + perl -i -pe "s|.*|${repo_url}|g" "$CSHARP_PROJ" + else + REPO_URL="${repo_url}" perl -i -pe 's|()|$1\n $ENV{REPO_URL}|' "$CSHARP_PROJ" + fi + + # Company + if grep -q "" "$CSHARP_PROJ"; then + perl -i -pe "s|.*|KeyNetra|g" "$CSHARP_PROJ" + else + perl -i -pe 's|()|$1\n KeyNetra|' "$CSHARP_PROJ" + fi + + # Authors + if grep -q "" "$CSHARP_PROJ"; then + perl -i -pe "s|.*|KeyNetra|g" "$CSHARP_PROJ" + else + perl -i -pe 's|()|$1\n KeyNetra|' "$CSHARP_PROJ" + fi + + # Package Project URL + if grep -q "" "$CSHARP_PROJ"; then + perl -i -pe "s|.*|${repo_url}|g" "$CSHARP_PROJ" + else + REPO_URL="${repo_url}" perl -i -pe 's|(.*)|$1\n $ENV{REPO_URL}|' "$CSHARP_PROJ" + fi + + # License + if grep -q "" "$CSHARP_PROJ"; then + perl -i -pe 's|.*|Apache-2.0|g' "$CSHARP_PROJ" + else + perl -i -pe 's|(.*)|$1\n Apache-2.0|' "$CSHARP_PROJ" + fi + + # Ensure NuGet README metadata is present exactly once. + perl -0i -pe 's@(?:\s*README.md\s*)+@\n@g' "$CSHARP_PROJ" + perl -0i -pe 's@\n\s*]*/>\s*@@g' "$CSHARP_PROJ" + perl -0i -pe 's@\s*\s*\s*@@g' "$CSHARP_PROJ" + + if ! grep -q "README.md" "$CSHARP_PROJ"; then + perl -0i -pe 's@@ README.md\n @' "$CSHARP_PROJ" + fi + + perl -0i -pe 's@(?:\s*\s*\s*\s*)+@\n@g' "$CSHARP_PROJ" + perl -0i -pe 's@@ \n \n \n@' "$CSHARP_PROJ" + + echo "CSharp .csproj metadata fixed." + +fi + + cat > "${ROOT_DIR}/sdks/csharp/src/KeyNetra.Client/KeyNetraClient.cs" <<'EOF' +namespace KeyNetra.Client; + +using KeyNetra.Client.Api; +using KeyNetra.Client.Client; + +/// +/// Unified entry point for the KeyNetra C# SDK. +/// +public sealed class KeyNetraClient +{ + /// + /// Access control and authorization operations. + /// + public AccessApi Access { get; } + + /// + /// Authentication and identity operations. + /// + public AuthApi Auth { get; } + + /// + /// Development and testing operations. + /// + public DevApi Dev { get; } + + /// + /// Service health and readiness operations. + /// + public HealthApi Health { get; } + + /// + /// Tenant, policy, and role management operations. + /// + public ManagementApi Management { get; } + + /// + /// Playground and interactive helper operations. + /// + public PlaygroundApi Playground { get; } + + /// + /// Creates a unified KeyNetra client for all generated API groups. + /// + /// The KeyNetra API base URL. + /// The API key used for both API key and bearer authentication. + public KeyNetraClient(string baseUrl, string apiKey) + { + var configuration = new Configuration + { + BasePath = baseUrl + }; + + configuration.DefaultHeaders["X-API-Key"] = apiKey; + configuration.DefaultHeaders["Authorization"] = $"Bearer {apiKey}"; + + // Use the simplified client initialization if possible + // Based on common OpenAPI C# generator patterns + Access = new AccessApi(configuration); + Auth = new AuthApi(configuration); + Dev = new DevApi(configuration); + Health = new HealthApi(configuration); + Management = new ManagementApi(configuration); + Playground = new PlaygroundApi(configuration); + } +} +EOF +} + +prepare_php() { + log_step "PHP" + local repo_url="https://github.com/keynetra/keynetra-client-php" + local docs_url="https://docs.keynetra.com/sdks/php" + generate_readme "PHP" "keynetra/client" "composer require keynetra/client" "use KeyNetra\Client\KeyNetraClient; + +\$client = new KeyNetraClient( + \"http://localhost:8080\", + \"YOUR_API_KEY\" +); + +// Perform an access check +\$decision = \$client->getAccessApi()->checkAccess(...);" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/php/README.md" +} + +prepare_ruby() { + log_step "Ruby" + local repo_url="https://github.com/keynetra/keynetra-client-ruby" + local docs_url="https://docs.keynetra.com/sdks/ruby" + + # Ensure the directory exists + mkdir -p "${ROOT_DIR}/sdks/ruby/lib/keynetra-client" + + # The generator might not have created the version file if we are using custom templates or specific options + # Let's ensure a version file exists so the gemspec doesn't fail + if [ ! -f "${ROOT_DIR}/sdks/ruby/lib/keynetra-client/version.rb" ]; then + cat > "${ROOT_DIR}/sdks/ruby/lib/keynetra-client/version.rb" < "${ROOT_DIR}/sdks/ruby/README.md" + + # Fix .gemspec metadata + if [ -f "${ROOT_DIR}/sdks/ruby/keynetra-client.gemspec" ]; then + perl -i -pe "s/s.summary = .*/s.summary = \"Official Ruby Client SDK for the KeyNetra authorization platform.\"/g" "${ROOT_DIR}/sdks/ruby/keynetra-client.gemspec" + perl -i -pe "s/s.authors = .*/s.authors = [\"SainathSapa\"]/g" "${ROOT_DIR}/sdks/ruby/keynetra-client.gemspec" + perl -i -pe "s/s.email = .*/s.email = [\"info.djsai\@gmail.com\"]/g" "${ROOT_DIR}/sdks/ruby/keynetra-client.gemspec" + fi +} + +prepare_kotlin() { + log_step "Kotlin" + local repo_url="https://github.com/keynetra/keynetra-client-kotlin" + local docs_url="https://docs.keynetra.com/sdks/kotlin" + + # Ensure gradlew is executable + if [ -f "${ROOT_DIR}/sdks/kotlin/gradlew" ]; then + chmod +x "${ROOT_DIR}/sdks/kotlin/gradlew" + fi + + # Add missing kotlinx-serialization-json dependency to build.gradle.kts + if [ -f "${ROOT_DIR}/sdks/kotlin/build.gradle.kts" ]; then + if ! grep -q "kotlinx-serialization-json" "${ROOT_DIR}/sdks/kotlin/build.gradle.kts"; then + # Find the dependencies block or a similar serialization core line + perl -i -pe 's/(implementation\("org.jetbrains.kotlinx:kotlinx-serialization-core:\$serialization_version"\))/$1\n implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:\$serialization_version")/' "${ROOT_DIR}/sdks/kotlin/build.gradle.kts" + fi + # Also ensure the serialization plugin is applied if missing + if ! grep -q "plugin.serialization" "${ROOT_DIR}/sdks/kotlin/build.gradle.kts"; then + perl -i -pe 's/(kotlin\("multiplatform"\))/$1\n kotlin("plugin.serialization") version "1.9.21"/' "${ROOT_DIR}/sdks/kotlin/build.gradle.kts" + fi + fi + + generate_readme "Kotlin" "keynetra-client-kotlin" "implementation(\"io.keynetra:keynetra-client-kotlin:${SDK_VERSION}\")" "import io.keynetra.client.KeyNetraClient + +val client = KeyNetraClient( + baseUrl = \"http://localhost:8080\", + apiKey = \"YOUR_API_KEY\" +) + +// Perform an access check +val decision = client.accessApi.checkAccess(...)" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/kotlin/README.md" +} + +prepare_swift() { + log_step "Swift" + local repo_url="https://github.com/keynetra/keynetra-client-swift" + local docs_url="https://docs.keynetra.com/sdks/swift" + generate_readme "Swift" "KeyNetraClient" "dependencies: [ + .package(url: \"${repo_url}.git\", from: \"${SDK_VERSION}\") +]" "import KeyNetraClient + +let client = KeyNetraClient( + baseUrl: \"http://localhost:8080\", + apiKey: \"YOUR_API_KEY\" +) + +// Perform an access check +client.accessApi.checkAccess(...)" "${repo_url}" "${docs_url}" > "${ROOT_DIR}/sdks/swift/README.md" +} + +prepare_python +prepare_typescript +prepare_go +prepare_java +prepare_rust +prepare_csharp +prepare_php +prepare_ruby +# prepare_kotlin +prepare_swift + +log_success "Prepared SDK package metadata and unified KeyNetraClient wrappers." diff --git a/templates/csharp-config.yaml b/templates/csharp-config.yaml new file mode 100644 index 0000000..02666e4 --- /dev/null +++ b/templates/csharp-config.yaml @@ -0,0 +1,13 @@ +packageName: KeyNetra.Client +packageVersion: 0.1.1 +packageCompany: KeyNetra +packageAuthors: KeyNetra +packageTitle: KeyNetra.Client +targetFramework: net8.0 +library: restsharp +nullableReferenceTypes: true +optionalProjectFile: false +packageTags: "keynetra;authorization;authz;permissions;sdk" +packageDescription: "Official C# SDK for the KeyNetra authorization platform. KeyNetra provides high-performance, distributed authorization as a service." +packageProjectUrl: "https://github.com/keynetra/keynetra-client-csharp" +packageLicenseExpression: "Apache-2.0" diff --git a/templates/go-config.yaml b/templates/go-config.yaml new file mode 100644 index 0000000..b94a604 --- /dev/null +++ b/templates/go-config.yaml @@ -0,0 +1,11 @@ +packageName: keynetra +packageVersion: 0.1.1 +moduleName: github.com/keynetra/keynetra-client-go +enumClassPrefix: true +generateInterfaces: true +hideGenerationTimestamp: true +withGoMod: true +packageDescription: "Official Go Client SDK for KeyNetra authorization platform." +packageAuthor: "KeyNetra" +packageEmail: "business.keynetra@gmail.com" +packageUrl: "https://github.com/keynetra/keynetra-client-go" diff --git a/templates/java-config.yaml b/templates/java-config.yaml new file mode 100644 index 0000000..0f68e27 --- /dev/null +++ b/templates/java-config.yaml @@ -0,0 +1,16 @@ +groupId: io.keynetra +artifactId: keynetra-client +artifactVersion: 0.1.1 +invokerPackage: io.keynetra.client +apiPackage: io.keynetra.client.api +modelPackage: io.keynetra.client.model +library: okhttp-gson +hideGenerationTimestamp: true +developerName: Sainath Sapa +developerEmail: business.keynetra@gmail.com +developerOrganization: KeyNetra +developerOrganizationUrl: https://keynetra.com +scmConnection: scm:git:git://github.com/keynetra/keynetra-client-java.git +scmDeveloperConnection: scm:git:ssh://github.com:keynetra/keynetra-client-java.git +scmUrl: https://github.com/keynetra/keynetra-client-java +artifactDescription: Official Java Client SDK for the KeyNetra authorization platform. diff --git a/templates/kotlin-config.yaml b/templates/kotlin-config.yaml new file mode 100644 index 0000000..df5dbc7 --- /dev/null +++ b/templates/kotlin-config.yaml @@ -0,0 +1,15 @@ +groupId: io.keynetra +artifactId: keynetra-client-kotlin +artifactVersion: 0.1.1 +packageName: io.keynetra.client +library: multiplatform +dateLibrary: kotlinx-datetime +hideGenerationTimestamp: true +developerName: Sainath Sapa +developerEmail: business.keynetra@gmail.com +developerOrganization: KeyNetra +developerOrganizationUrl: https://keynetra.com +scmConnection: scm:git:git://github.com/keynetra/keynetra-client-kotlin.git +scmDeveloperConnection: scm:git:ssh://github.com:keynetra/keynetra-client-kotlin.git +scmUrl: https://github.com/keynetra/keynetra-client-kotlin +artifactDescription: Official Kotlin Multiplatform Client SDK for the KeyNetra authorization platform. diff --git a/templates/php-config.yaml b/templates/php-config.yaml new file mode 100644 index 0000000..e51b62e --- /dev/null +++ b/templates/php-config.yaml @@ -0,0 +1,13 @@ +invokerPackage: KeyNetra\Client +packageName: keynetra-client +packageVersion: 0.1.1 +variableNamingConvention: camelCase +hideGenerationTimestamp: true +composerPackageName: keynetra/client +developerName: Sainath Sapa +developerEmail: business.keynetra@gmail.com +developerOrganization: KeyNetra +developerOrganizationUrl: https://keynetra.com +packageUrl: https://github.com/keynetra/keynetra-client-php +artifactDescription: Official PHP Client SDK for the KeyNetra authorization platform. +licenseName: Apache-2.0 diff --git a/templates/python-config.yaml b/templates/python-config.yaml new file mode 100644 index 0000000..d5a9dcb --- /dev/null +++ b/templates/python-config.yaml @@ -0,0 +1,11 @@ +packageName: keynetra_client +projectName: keynetra-client +packageVersion: 0.1.1 +packageUrl: https://github.com/keynetra/keynetra-client-python +library: urllib3 +hideGenerationTimestamp: true +authorName: Sainath.Sapa +authorEmail: info.djsai@gmail.com +packageDescription: Official Python Client SDK for the KeyNetra authorization platform. +licenseName: Apache-2.0 +usePydantic: false diff --git a/templates/ruby-config.yaml b/templates/ruby-config.yaml new file mode 100644 index 0000000..fa73ed9 --- /dev/null +++ b/templates/ruby-config.yaml @@ -0,0 +1,9 @@ +gemName: keynetra-client +moduleName: KeyNetra +gemVersion: 0.1.1 +hideGenerationTimestamp: true +gemAuthor: SainathSapa +gemAuthorEmail: info.djsai@gmail.com +gemDescription: Official Ruby SDK for the KeyNetra authorization platform. +gemHomepage: https://github.com/keynetra/keynetra-client-ruby +gemLicense: Apache-2.0 diff --git a/templates/rust-config.yaml b/templates/rust-config.yaml new file mode 100644 index 0000000..55f562c --- /dev/null +++ b/templates/rust-config.yaml @@ -0,0 +1,10 @@ +packageName: keynetra-client +packageVersion: 0.1.1 +library: reqwest +supportAsync: true +hideGenerationTimestamp: true +packageAuthors: "KeyNetra " +packageDescription: "Official Rust SDK for the KeyNetra authorization platform." +packageHomepage: "https://keynetra.com" +packageRepository: "https://github.com/keynetra/keynetra-client-rust" +packageLicense: "Apache-2.0" diff --git a/templates/swift-config.yaml b/templates/swift-config.yaml new file mode 100644 index 0000000..4a342e4 --- /dev/null +++ b/templates/swift-config.yaml @@ -0,0 +1,10 @@ +projectName: KeyNetraClient +podName: KeyNetraClient +moduleName: KeyNetraClient +hideGenerationTimestamp: true +podAuthors: KeyNetra +podSummary: Official Swift Client SDK for the KeyNetra authorization platform. +podDescription: "KeyNetra provides high-performance, distributed authorization as a service. This SDK allows Swift applications to integrate with KeyNetra for access control." +podHomepage: https://keynetra.com +podSource: https://github.com/keynetra/keynetra-client-swift +podLicense: Apache-2.0 diff --git a/templates/typescript-config.yaml b/templates/typescript-config.yaml new file mode 100644 index 0000000..3048b6a --- /dev/null +++ b/templates/typescript-config.yaml @@ -0,0 +1,12 @@ +npmName: "@keynetra/client" +npmVersion: 0.1.1 +supportsES6: true +typescriptThreePlus: true +withInterfaces: true +useSingleRequestParameter: true +enumNameSuffix: Enum +packageDescription: Official TypeScript SDK for the KeyNetra authorization platform. +authorName: KeyNetra +authorEmail: business.keynetra@gmail.com +packageRepository: https://github.com/keynetra/keynetra-client-typescript +packageLicense: Apache-2.0 diff --git a/tests/csharp/TestInstantiation.cs b/tests/csharp/TestInstantiation.cs new file mode 100644 index 0000000..25eb651 --- /dev/null +++ b/tests/csharp/TestInstantiation.cs @@ -0,0 +1,21 @@ +using System; +using KeyNetra.Client; + +namespace KeyNetra.Tests +{ + class Program + { + static void Main(string[] args) + { + try { + var client = new KeyNetraClient("http://localhost:8080", "test-key"); + if (client != null) { + Console.WriteLine("C# SDK: Client instantiated successfully."); + } + } catch (Exception e) { + Console.Error.WriteLine("C# SDK: Error: " + e.Message); + Environment.Exit(1); + } + } + } +} diff --git a/tests/go/go.mod b/tests/go/go.mod new file mode 100644 index 0000000..71e722e --- /dev/null +++ b/tests/go/go.mod @@ -0,0 +1,5 @@ +module tests/go + +go 1.21.0 + +replace github.com/keynetra/keynetra-client-go => ../../sdks/go diff --git a/tests/go/test_instantiation.go b/tests/go/test_instantiation.go new file mode 100644 index 0000000..239e94c --- /dev/null +++ b/tests/go/test_instantiation.go @@ -0,0 +1,31 @@ +package main + +import ( + "fmt" + "os" + + "github.com/keynetra/keynetra-client-go" +) + +func testClientInstantiation() bool { + defer func() { + if r := recover(); r != nil { + fmt.Printf("Go SDK: Panic: %v\n", r) + } + }() + + client := keynetra.NewKeyNetraClient("http://localhost:8080", "test-key") + if client != nil { + fmt.Println("Go SDK: Client instantiated successfully.") + return true + } + return false +} + +func main() { + if testClientInstantiation() { + os.Exit(0) + } else { + os.Exit(1) + } +} diff --git a/tests/java/TestInstantiation.java b/tests/java/TestInstantiation.java new file mode 100644 index 0000000..9e74d9b --- /dev/null +++ b/tests/java/TestInstantiation.java @@ -0,0 +1,15 @@ +import io.keynetra.client.KeyNetraClient; + +public class TestInstantiation { + public static void main(String[] args) { + try { + KeyNetraClient client = new KeyNetraClient("http://localhost:8080", "test-key"); + if (client != null) { + System.out.println("Java SDK: Client instantiated successfully."); + } + } catch (Exception e) { + System.err.println("Java SDK: Error: " + e.getMessage()); + System.exit(1); + } + } +} diff --git a/tests/python/test_full.py b/tests/python/test_full.py new file mode 100644 index 0000000..166bd2a --- /dev/null +++ b/tests/python/test_full.py @@ -0,0 +1,37 @@ +import sys +import os +import unittest +import time + +# Add generated SDK to path +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../sdks/python"))) + +from keynetra_client import KeyNetraClient + +class TestKeyNetraPythonSDK(unittest.TestCase): + def setUp(self): + self.base_url = "http://localhost:8080" + self.api_key = "test-key" + self.client = KeyNetraClient(base_url=self.base_url, api_key=self.api_key) + + def test_health_check(self): + print(f"\nTesting Health Check against {self.base_url}...") + try: + # The health API is at self.client.health + response = self.client.health.health_health_get() + print(f"Health Response: {response}") + self.assertIsNotNone(response) + except Exception as e: + self.fail(f"Health check failed: {e}") + + def test_liveness(self): + print(f"\nTesting Liveness Check against {self.base_url}...") + try: + response = self.client.health.liveness_health_live_get() + print(f"Liveness Response: {response}") + self.assertIsNotNone(response) + except Exception as e: + self.fail(f"Liveness check failed: {e}") + +if __name__ == "__main__": + unittest.main() diff --git a/tests/python/test_instantiation.py b/tests/python/test_instantiation.py new file mode 100644 index 0000000..b6e86f7 --- /dev/null +++ b/tests/python/test_instantiation.py @@ -0,0 +1,36 @@ +import sys +import os + +# Add generated SDK to path +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "../../sdks/python"))) + +def test_client_instantiation(): + try: + from keynetra_client import KeyNetraClient + client = KeyNetraClient(base_url="http://localhost:8080", api_key="test-key") + + # Check if all APIs are initialized + assert client.access is not None + assert client.auth is not None + assert client.dev is not None + assert client.health is not None + assert client.management is not None + assert client.playground is not None + + print("Python SDK: Client instantiated successfully with all APIs.") + return True + except ImportError as e: + print(f"Python SDK: Import error: {e}") + return False + except AssertionError as e: + print(f"Python SDK: Assertion error: {e}") + return False + except Exception as e: + print(f"Python SDK: Unexpected error: {e}") + return False + +if __name__ == "__main__": + if test_client_instantiation(): + sys.exit(0) + else: + sys.exit(1) diff --git a/tests/rust/test_instantiation.rs b/tests/rust/test_instantiation.rs new file mode 100644 index 0000000..20d9207 --- /dev/null +++ b/tests/rust/test_instantiation.rs @@ -0,0 +1,8 @@ +extern crate keynetra_client; + +use keynetra_client::keynetra_client::KeyNetraClient; + +fn main() { + let client = KeyNetraClient::new("http://localhost:8080", "test-key"); + println!("Rust SDK: Client instantiated successfully."); +} diff --git a/tests/typescript/test_instantiation.ts b/tests/typescript/test_instantiation.ts new file mode 100644 index 0000000..4e78dfb --- /dev/null +++ b/tests/typescript/test_instantiation.ts @@ -0,0 +1,23 @@ +import { KeyNetraClient } from "../../sdks/typescript/src/keynetra-client"; + +function testClientInstantiation() { + try { + const client = new KeyNetraClient("http://localhost:8080", "test-key"); + + // Check if all APIs are initialized + if (!client.access) throw new Error("access API missing"); + if (!client.auth) throw new Error("auth API missing"); + if (!client.dev) throw new Error("dev API missing"); + if (!client.health) throw new Error("health API missing"); + if (!client.management) throw new Error("management API missing"); + if (!client.playground) throw new Error("playground API missing"); + + console.log("TypeScript SDK: Client instantiated successfully with all APIs."); + return true; + } catch (error) { + console.error("TypeScript SDK: Error:", error); + return false; + } +} + +testClientInstantiation();