apikee 0.0.7__tar.gz → 0.1.2.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apikee-0.1.2.dev0/.github/CODEOWNERS +3 -0
- apikee-0.1.2.dev0/.github/ISSUE_TEMPLATE/bug_report.yml +41 -0
- apikee-0.1.2.dev0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- apikee-0.1.2.dev0/.github/ISSUE_TEMPLATE/feature_request.yml +22 -0
- apikee-0.1.2.dev0/.github/PULL_REQUEST_TEMPLATE.md +9 -0
- apikee-0.1.2.dev0/.github/dependabot.yml +15 -0
- apikee-0.1.2.dev0/.github/workflows/release.yml +196 -0
- apikee-0.1.2.dev0/.gitignore +32 -0
- apikee-0.1.2.dev0/.release-please-manifest.json +3 -0
- apikee-0.1.2.dev0/AGENTS.md +64 -0
- apikee-0.1.2.dev0/CONTRIBUTING.md +80 -0
- apikee-0.1.2.dev0/LICENSE +21 -0
- apikee-0.1.2.dev0/PKG-INFO +166 -0
- apikee-0.1.2.dev0/README.md +132 -0
- apikee-0.1.2.dev0/apikee/__init__.py +33 -0
- apikee-0.1.2.dev0/apikee/core.py +269 -0
- apikee-0.1.2.dev0/apikee/crypto.py +114 -0
- apikee-0.1.2.dev0/apikee/fastapi.py +170 -0
- apikee-0.1.2.dev0/apikee/flask.py +138 -0
- apikee-0.1.2.dev0/apikee/key.py +287 -0
- apikee-0.1.2.dev0/apikee/server.py +232 -0
- apikee-0.1.2.dev0/examples/fastapi/README.md +22 -0
- apikee-0.1.2.dev0/examples/fastapi/main.py +47 -0
- apikee-0.1.2.dev0/examples/flask/README.md +20 -0
- apikee-0.1.2.dev0/examples/flask/app.py +47 -0
- apikee-0.1.2.dev0/examples/starlette/README.md +12 -0
- apikee-0.1.2.dev0/examples/starlette/app.py +41 -0
- apikee-0.1.2.dev0/pyproject.toml +40 -0
- apikee-0.1.2.dev0/pytest.ini +3 -0
- apikee-0.1.2.dev0/release-please-config.json +22 -0
- apikee-0.1.2.dev0/tests/smoke.py +87 -0
- apikee-0.1.2.dev0/tests/test_apikee.py +206 -0
- apikee-0.0.7/PKG-INFO +0 -140
- apikee-0.0.7/README.md +0 -130
- apikee-0.0.7/apikee/__init__.py +0 -4
- apikee-0.0.7/apikee/config.py +0 -30
- apikee-0.0.7/apikee/middleware.py +0 -42
- apikee-0.0.7/apikee/security.py +0 -56
- apikee-0.0.7/apikee/server/client.py +0 -113
- apikee-0.0.7/apikee/server/error.py +0 -19
- apikee-0.0.7/apikee/server/types.py +0 -42
- apikee-0.0.7/apikee/test.py +0 -28
- apikee-0.0.7/apikee.egg-info/PKG-INFO +0 -140
- apikee-0.0.7/apikee.egg-info/SOURCES.txt +0 -15
- apikee-0.0.7/apikee.egg-info/dependency_links.txt +0 -1
- apikee-0.0.7/apikee.egg-info/top_level.txt +0 -1
- apikee-0.0.7/setup.cfg +0 -4
- apikee-0.0.7/setup.py +0 -15
- {apikee-0.0.7/apikee/server → apikee-0.1.2.dev0/tests}/__init__.py +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a problem with the apikee Python package
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: description
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened?
|
|
9
|
+
description: A clear description of the bug.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: reproduce
|
|
14
|
+
attributes:
|
|
15
|
+
label: Steps to reproduce
|
|
16
|
+
placeholder: |
|
|
17
|
+
1. ...
|
|
18
|
+
2. ...
|
|
19
|
+
3. ...
|
|
20
|
+
validations:
|
|
21
|
+
required: true
|
|
22
|
+
- type: textarea
|
|
23
|
+
id: expected
|
|
24
|
+
attributes:
|
|
25
|
+
label: Expected behavior
|
|
26
|
+
validations:
|
|
27
|
+
required: false
|
|
28
|
+
- type: input
|
|
29
|
+
id: version
|
|
30
|
+
attributes:
|
|
31
|
+
label: Package version
|
|
32
|
+
placeholder: e.g. apikee==0.1.2 (or a .devN pre-release)
|
|
33
|
+
validations:
|
|
34
|
+
required: false
|
|
35
|
+
- type: textarea
|
|
36
|
+
id: env
|
|
37
|
+
attributes:
|
|
38
|
+
label: Environment
|
|
39
|
+
placeholder: Python version, optional extras installed (fast/server/fastapi/all), OS, etc.
|
|
40
|
+
validations:
|
|
41
|
+
required: false
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea for the apikee Python package
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: What problem does this solve?
|
|
9
|
+
validations:
|
|
10
|
+
required: true
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: solution
|
|
13
|
+
attributes:
|
|
14
|
+
label: Proposed solution
|
|
15
|
+
validations:
|
|
16
|
+
required: false
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: alternatives
|
|
19
|
+
attributes:
|
|
20
|
+
label: Alternatives considered
|
|
21
|
+
validations:
|
|
22
|
+
required: false
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this PR do, and why? -->
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] PR title follows [Conventional Commits](https://www.conventionalcommits.org/) (e.g. `feat: ...`, `fix: ...`)
|
|
8
|
+
- [ ] `pytest -q` and `python -m build` pass locally
|
|
9
|
+
- [ ] Documentation updated (README, CONTRIBUTING.md) if needed
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
name: python-cicd
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
paths:
|
|
6
|
+
- "apikee/**"
|
|
7
|
+
- "tests/**"
|
|
8
|
+
- "pyproject.toml"
|
|
9
|
+
- ".github/workflows/**"
|
|
10
|
+
push:
|
|
11
|
+
branches:
|
|
12
|
+
- main
|
|
13
|
+
- dev
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
id-token: write
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
validate:
|
|
22
|
+
name: Validate, Test, Package
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup Python
|
|
30
|
+
uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.11"
|
|
33
|
+
cache: pip
|
|
34
|
+
cache-dependency-path: pyproject.toml
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
pip install -e .[all]
|
|
40
|
+
pip install build twine pytest pytest-asyncio httpx
|
|
41
|
+
|
|
42
|
+
- name: Test
|
|
43
|
+
run: pytest -q
|
|
44
|
+
|
|
45
|
+
- name: Build package
|
|
46
|
+
run: python -m build
|
|
47
|
+
|
|
48
|
+
- name: Check artifacts
|
|
49
|
+
run: twine check dist/*
|
|
50
|
+
|
|
51
|
+
- name: Upload package artifact (PR)
|
|
52
|
+
if: github.event_name == 'pull_request'
|
|
53
|
+
uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: python-package-${{ github.event.pull_request.number }}
|
|
56
|
+
path: dist/*
|
|
57
|
+
if-no-files-found: error
|
|
58
|
+
|
|
59
|
+
- name: Dependency review (PR)
|
|
60
|
+
if: github.event_name == 'pull_request'
|
|
61
|
+
uses: actions/dependency-review-action@v4
|
|
62
|
+
|
|
63
|
+
- name: Vulnerability scan (Trivy)
|
|
64
|
+
uses: aquasecurity/trivy-action@v0.36.0
|
|
65
|
+
with:
|
|
66
|
+
scan-type: fs
|
|
67
|
+
scan-ref: .
|
|
68
|
+
format: table
|
|
69
|
+
severity: CRITICAL,HIGH
|
|
70
|
+
ignore-unfixed: true
|
|
71
|
+
exit-code: 1
|
|
72
|
+
|
|
73
|
+
pr-title:
|
|
74
|
+
name: PR Title (Conventional Commits)
|
|
75
|
+
if: github.event_name == 'pull_request'
|
|
76
|
+
runs-on: ubuntu-latest
|
|
77
|
+
permissions:
|
|
78
|
+
pull-requests: read
|
|
79
|
+
steps:
|
|
80
|
+
- uses: amannn/action-semantic-pull-request@v5
|
|
81
|
+
env:
|
|
82
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
83
|
+
|
|
84
|
+
release-please:
|
|
85
|
+
name: Release Please
|
|
86
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
permissions:
|
|
89
|
+
contents: write
|
|
90
|
+
pull-requests: write
|
|
91
|
+
outputs:
|
|
92
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
93
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
94
|
+
steps:
|
|
95
|
+
- uses: googleapis/release-please-action@v4
|
|
96
|
+
id: release
|
|
97
|
+
with:
|
|
98
|
+
config-file: release-please-config.json
|
|
99
|
+
manifest-file: .release-please-manifest.json
|
|
100
|
+
|
|
101
|
+
publish-dev:
|
|
102
|
+
name: Publish Dev (dev)
|
|
103
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/dev'
|
|
104
|
+
needs: validate
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
|
|
107
|
+
steps:
|
|
108
|
+
- name: Checkout
|
|
109
|
+
uses: actions/checkout@v4
|
|
110
|
+
|
|
111
|
+
- name: Setup Python
|
|
112
|
+
uses: actions/setup-python@v5
|
|
113
|
+
with:
|
|
114
|
+
python-version: "3.11"
|
|
115
|
+
cache: pip
|
|
116
|
+
cache-dependency-path: pyproject.toml
|
|
117
|
+
|
|
118
|
+
- name: Install build tools
|
|
119
|
+
run: |
|
|
120
|
+
python -m pip install --upgrade pip
|
|
121
|
+
pip install build twine
|
|
122
|
+
|
|
123
|
+
- name: Compute next dev version
|
|
124
|
+
run: |
|
|
125
|
+
python - <<'PY'
|
|
126
|
+
import json, re, pathlib, urllib.request
|
|
127
|
+
|
|
128
|
+
text = pathlib.Path("pyproject.toml").read_text()
|
|
129
|
+
m = re.search(r'^version\s*=\s*"([^"]+)"', text, re.M)
|
|
130
|
+
if not m:
|
|
131
|
+
raise SystemExit("Could not find version in pyproject.toml")
|
|
132
|
+
base = re.sub(r"\.dev\d+$", "", m.group(1))
|
|
133
|
+
|
|
134
|
+
next_num = 0
|
|
135
|
+
try:
|
|
136
|
+
with urllib.request.urlopen("https://pypi.org/pypi/apikee/json", timeout=10) as r:
|
|
137
|
+
releases = json.loads(r.read()).get("releases", {})
|
|
138
|
+
pat = re.compile(r"^" + re.escape(base) + r"\.dev(\d+)$")
|
|
139
|
+
nums = [int(mm.group(1)) for v in releases for mm in [pat.match(v)] if mm]
|
|
140
|
+
if nums:
|
|
141
|
+
next_num = max(nums) + 1
|
|
142
|
+
except Exception:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
dev_version = f"{base}.dev{next_num}"
|
|
146
|
+
new_text = re.sub(r'^version\s*=\s*"[^"]+"', f'version = "{dev_version}"', text, count=1, flags=re.M)
|
|
147
|
+
pathlib.Path("pyproject.toml").write_text(new_text)
|
|
148
|
+
print(f"Dev version: {dev_version}")
|
|
149
|
+
PY
|
|
150
|
+
|
|
151
|
+
- name: Build package
|
|
152
|
+
run: python -m build
|
|
153
|
+
|
|
154
|
+
- name: Check artifacts
|
|
155
|
+
run: twine check dist/*
|
|
156
|
+
|
|
157
|
+
- name: Publish dev to PyPI (Trusted Publishing)
|
|
158
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
159
|
+
with:
|
|
160
|
+
packages-dir: dist/
|
|
161
|
+
|
|
162
|
+
publish-release:
|
|
163
|
+
name: Publish Release (main)
|
|
164
|
+
needs: [validate, release-please]
|
|
165
|
+
if: |
|
|
166
|
+
needs.validate.result == 'success' &&
|
|
167
|
+
needs.release-please.result == 'success' &&
|
|
168
|
+
needs.release-please.outputs.release_created == 'true'
|
|
169
|
+
runs-on: ubuntu-latest
|
|
170
|
+
|
|
171
|
+
steps:
|
|
172
|
+
- name: Checkout
|
|
173
|
+
uses: actions/checkout@v4
|
|
174
|
+
|
|
175
|
+
- name: Setup Python
|
|
176
|
+
uses: actions/setup-python@v5
|
|
177
|
+
with:
|
|
178
|
+
python-version: "3.11"
|
|
179
|
+
cache: pip
|
|
180
|
+
cache-dependency-path: pyproject.toml
|
|
181
|
+
|
|
182
|
+
- name: Install build tools
|
|
183
|
+
run: |
|
|
184
|
+
python -m pip install --upgrade pip
|
|
185
|
+
pip install build twine
|
|
186
|
+
|
|
187
|
+
- name: Build package
|
|
188
|
+
run: python -m build
|
|
189
|
+
|
|
190
|
+
- name: Check artifacts
|
|
191
|
+
run: twine check dist/*
|
|
192
|
+
|
|
193
|
+
- name: Publish release to PyPI (Trusted Publishing)
|
|
194
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
195
|
+
with:
|
|
196
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Python caches
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.mypy_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
|
|
14
|
+
# Build outputs
|
|
15
|
+
dist/
|
|
16
|
+
build/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
|
|
19
|
+
# Coverage
|
|
20
|
+
.coverage
|
|
21
|
+
coverage.xml
|
|
22
|
+
htmlcov/
|
|
23
|
+
|
|
24
|
+
# Environment
|
|
25
|
+
.env
|
|
26
|
+
.env.*
|
|
27
|
+
!.env.example
|
|
28
|
+
|
|
29
|
+
# Editor / OS
|
|
30
|
+
.DS_Store
|
|
31
|
+
.vscode/
|
|
32
|
+
.idea/
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# AGENTS.md — apikee Python
|
|
2
|
+
|
|
3
|
+
This file orients AI coding agents (and humans) working in this repository.
|
|
4
|
+
|
|
5
|
+
## What this project is
|
|
6
|
+
|
|
7
|
+
`apikee` is an API key creation/validation plugin for Python — local-only by default
|
|
8
|
+
(zero dependencies), with optional integrations for FastAPI, Flask, and Starlette/ASGI.
|
|
9
|
+
It creates and verifies HMAC-signed API keys (`apikee_<claims>.<signature>`) carrying
|
|
10
|
+
tenant, scopes, and expiry, and can optionally talk to a self-hosted Apikee server for
|
|
11
|
+
key rotation, encrypted payloads (X25519 + AES-256-GCM), and RSA-signed requests. See
|
|
12
|
+
[README.md](./README.md) for usage examples and environment variables.
|
|
13
|
+
|
|
14
|
+
## Build, test, lint
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
18
|
+
pip install -e .[all] # all extras: fast (msgpack), server (cryptography), fastapi
|
|
19
|
+
pytest -q
|
|
20
|
+
python -m build # build sdist + wheel
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
There is no separate lint step configured.
|
|
24
|
+
|
|
25
|
+
## Source layout
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
apikee/
|
|
29
|
+
__init__.py Public API surface — Apikee, ApikeeClaims, get_apikee(), etc.
|
|
30
|
+
core.py Apikee class — create()/verify()/protect(), config + env fallbacks
|
|
31
|
+
key.py Local key encode/decode/HMAC verify, RSA request signing (zero I/O)
|
|
32
|
+
crypto.py X25519 ECDH + AES-256-GCM encrypted channel for server mode
|
|
33
|
+
server.py ApikeeServer — HTTP client for a self-hosted Apikee instance
|
|
34
|
+
fastapi.py SecuredFastAPI, ApikeeDepends(), require_scope() for FastAPI
|
|
35
|
+
flask.py init_apikee(), apikee_required, require_scope() for Flask
|
|
36
|
+
tests/
|
|
37
|
+
test_apikee.py Unit tests (pytest)
|
|
38
|
+
smoke.py Smoke test for the installed package
|
|
39
|
+
examples/
|
|
40
|
+
fastapi/ Todo API example using apikee.fastapi
|
|
41
|
+
flask/ Notes API example using apikee.flask
|
|
42
|
+
starlette/ Items API example using Apikee().middleware (ASGI)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Conventions
|
|
46
|
+
|
|
47
|
+
- **Local-only mode has zero runtime dependencies.** Optional extras
|
|
48
|
+
(`fast`/`server`/`fastapi`, see `pyproject.toml [project.optional-dependencies]`) are
|
|
49
|
+
required only for msgpack serialisation, the encrypted server channel, and FastAPI
|
|
50
|
+
integration respectively.
|
|
51
|
+
- `Apikee(...)` and `init_apikee()`/`SecuredFastAPI()` are zero-config — all server-mode
|
|
52
|
+
and crypto options fall back to `APIKEE_*` environment variables when not passed
|
|
53
|
+
explicitly (see `core.py`'s module docstring for the full list).
|
|
54
|
+
- Commit messages and PR titles follow [Conventional Commits](https://www.conventionalcommits.org/)
|
|
55
|
+
(`feat:`, `fix:`, `chore:`, `docs:`, `feat!:` for breaking changes).
|
|
56
|
+
- Branching: `dev` is the integration branch; every push queries the PyPI JSON API for the
|
|
57
|
+
latest published `.devN` counter with the same base version, increments it, and publishes.
|
|
58
|
+
`main` is the stable branch. **release-please** owns `version` in `pyproject.toml` and
|
|
59
|
+
`CHANGELOG.md` — never hand-edit either.
|
|
60
|
+
|
|
61
|
+
## Contribution process
|
|
62
|
+
|
|
63
|
+
For the branch/PR workflow, release process, and required CI secrets and runtime
|
|
64
|
+
environment variables, see [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Contributing — apikee Python
|
|
2
|
+
|
|
3
|
+
Thanks for contributing! This guide covers the contribution workflow, branch
|
|
4
|
+
and release process, and required secrets/environment variables.
|
|
5
|
+
|
|
6
|
+
For build/test commands, project layout, and coding conventions, see
|
|
7
|
+
[AGENTS.md](./AGENTS.md) — the same reference used by AI coding agents.
|
|
8
|
+
|
|
9
|
+
## Local setup
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python3 -m venv .venv && source .venv/bin/activate
|
|
13
|
+
pip install -e .[all]
|
|
14
|
+
pytest -q
|
|
15
|
+
python -m build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Branch & PR flow
|
|
19
|
+
|
|
20
|
+
| Branch | Purpose | On push |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| `dev` | integration branch — branch your work from here | publishes a `.devN` pre-release to PyPI (`pip install --pre apikee`) |
|
|
23
|
+
| `main` | stable branch, protected | release-please opens/updates a release PR; merging it publishes the stable release |
|
|
24
|
+
|
|
25
|
+
1. Branch from `dev`, naming it after the [Conventional Commits](https://www.conventionalcommits.org/)
|
|
26
|
+
type it corresponds to: `feature/<short-description>` (`feat:`), `fix/<short-description>`
|
|
27
|
+
(`fix:`), `chore/<short-description>` (`chore:`), `docs/<short-description>` (`docs:`).
|
|
28
|
+
2. Open a PR into `dev` (or `main` for urgent hotfixes). CI runs the test suite, builds the
|
|
29
|
+
package, runs a dependency review, and scans for vulnerabilities (Trivy).
|
|
30
|
+
3. **PR titles must follow Conventional Commits** (`type(scope?): description`) — a bot
|
|
31
|
+
checks this on open/edit. Examples: `feat: add async client support`, `fix(server):
|
|
32
|
+
correct signature verification`, `feat!: rename ApikeeClient constructor argument`
|
|
33
|
+
(the `!` marks a breaking change and triggers a major version bump).
|
|
34
|
+
4. `main` and `dev` are protected branches — all changes land via a reviewed PR that
|
|
35
|
+
passes CI.
|
|
36
|
+
|
|
37
|
+
## Releases
|
|
38
|
+
|
|
39
|
+
Versioning and `CHANGELOG.md` are fully automated by
|
|
40
|
+
[release-please](https://github.com/googleapis/release-please) from Conventional Commits
|
|
41
|
+
PR titles — never hand-edit `version` in `pyproject.toml` or commit dev versions.
|
|
42
|
+
|
|
43
|
+
- **Push to `dev`** → CI queries the PyPI JSON API for the latest published `.devN` version
|
|
44
|
+
with the same base (e.g. `0.1.2`), increments the counter by one, and publishes it to PyPI.
|
|
45
|
+
The first push for a new base starts at `0`. Install with `pip install --pre apikee`.
|
|
46
|
+
- **Merging the release-please PR on `main`** → CI publishes the stable release to PyPI.
|
|
47
|
+
PEP 440 guarantees `1.0.0 > 1.0.0.devN`, so `pip install apikee` always resolves to
|
|
48
|
+
the stable release. No additional deprecation step is needed.
|
|
49
|
+
|
|
50
|
+
## Secrets & environment
|
|
51
|
+
|
|
52
|
+
### CI/CD secrets (GitHub Actions)
|
|
53
|
+
|
|
54
|
+
| Secret | Used for | Notes |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `GITHUB_TOKEN` | release-please, PR title check | auto-provided by GitHub Actions, no setup needed |
|
|
57
|
+
| *(none)* | PyPI publish | uses PyPI Trusted Publishing (OIDC) via `id-token: write` — no secret to configure, but the `apikee` project on PyPI must have a Trusted Publisher set up for `apikee-dev/python` |
|
|
58
|
+
|
|
59
|
+
### Runtime environment variables
|
|
60
|
+
|
|
61
|
+
These configure the `apikee` package itself (used by the examples, tests, and any app
|
|
62
|
+
that depends on it):
|
|
63
|
+
|
|
64
|
+
| Variable | Required | Purpose |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `APIKEE_SECRET` | yes\* | HMAC signing secret(s) used for local key creation/verification |
|
|
67
|
+
| `APIKEE_BASE_URL` | no | URL of a self-hosted Apikee instance — enables server mode |
|
|
68
|
+
| `APIKEE_SERVER_KEY` | no | API key for the Apikee instance (server mode) |
|
|
69
|
+
| `APIKEE_PROJECT_ENV` | no | project-env slug (server mode) |
|
|
70
|
+
| `APIKEE_SERVER_PUBLIC_KEY` | no | X25519 public key (base64) — enables payload encryption |
|
|
71
|
+
| `APIKEE_PRIVATE_KEY` | no | RSA private key (PEM) — signs server validation requests |
|
|
72
|
+
|
|
73
|
+
\* Not required if you only use server mode (`APIKEE_BASE_URL` + `APIKEE_SERVER_KEY`),
|
|
74
|
+
since the server validates keys remotely.
|
|
75
|
+
|
|
76
|
+
For local development, create a `.env` file (gitignored) with at least:
|
|
77
|
+
|
|
78
|
+
```env
|
|
79
|
+
APIKEE_SECRET=replace-with-strong-random-secret
|
|
80
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 apikee
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: apikee
|
|
3
|
+
Version: 0.1.2.dev0
|
|
4
|
+
Summary: API key creation, validation & developer platform integration
|
|
5
|
+
Project-URL: Homepage, https://github.com/apikee-dev/python
|
|
6
|
+
Project-URL: Repository, https://github.com/apikee-dev/python
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: api-key,authentication,middleware,security
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
19
|
+
Classifier: Topic :: Security
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Requires-Dist: cryptography>=41.0; extra == 'all'
|
|
23
|
+
Requires-Dist: fastapi>=0.100; extra == 'all'
|
|
24
|
+
Requires-Dist: msgpack>=1.0; extra == 'all'
|
|
25
|
+
Requires-Dist: starlette>=0.27; extra == 'all'
|
|
26
|
+
Provides-Extra: fast
|
|
27
|
+
Requires-Dist: msgpack>=1.0; extra == 'fast'
|
|
28
|
+
Provides-Extra: fastapi
|
|
29
|
+
Requires-Dist: fastapi>=0.100; extra == 'fastapi'
|
|
30
|
+
Requires-Dist: starlette>=0.27; extra == 'fastapi'
|
|
31
|
+
Provides-Extra: server
|
|
32
|
+
Requires-Dist: cryptography>=41.0; extra == 'server'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# apikee · Python
|
|
36
|
+
|
|
37
|
+
[](https://pypi.org/project/apikee/)
|
|
38
|
+
|
|
39
|
+
API key plugin for Python — FastAPI, Flask, and Starlette.
|
|
40
|
+
|
|
41
|
+
## Install
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install apikee # local mode, zero deps
|
|
45
|
+
pip install "apikee[fastapi]" # + FastAPI middleware
|
|
46
|
+
pip install "apikee[server]" # + encrypted server channel
|
|
47
|
+
pip install "apikee[all]" # everything
|
|
48
|
+
pip install --pre apikee # latest dev pre-release
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configure
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
export APIKEE_SECRET=$(openssl rand -hex 32)
|
|
55
|
+
|
|
56
|
+
# Optional server mode — point to your self-hosted Apikee instance
|
|
57
|
+
export APIKEE_BASE_URL=https://apikee.example.com/api/v1
|
|
58
|
+
export APIKEE_SERVER_KEY=sk_...
|
|
59
|
+
export APIKEE_PROJECT_ENV=my-api-production
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## FastAPI
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from apikee.fastapi import SecuredFastAPI, ApikeeDepends, require_scope
|
|
66
|
+
from apikee import ApikeeClaims
|
|
67
|
+
from fastapi import Depends
|
|
68
|
+
|
|
69
|
+
app = SecuredFastAPI() # reads APIKEE_SECRET — done
|
|
70
|
+
|
|
71
|
+
@app.post("/keys") # public endpoint — issue keys to customers
|
|
72
|
+
def create_key(tenant: str, scopes: str = "read,write"):
|
|
73
|
+
key = app.apikee.create(tenant, scopes=scopes.split(","))
|
|
74
|
+
return {"key": key} # store it — returned once
|
|
75
|
+
|
|
76
|
+
@app.get("/data")
|
|
77
|
+
def get_data(claims: ApikeeClaims = ApikeeDepends()):
|
|
78
|
+
return {"tenant": claims.tenant, "scopes": claims.scopes}
|
|
79
|
+
|
|
80
|
+
@app.delete("/admin", dependencies=[Depends(require_scope("admin"))])
|
|
81
|
+
def admin_action(): ...
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Open `/docs` — every endpoint shows the 🔒 lock. Click **Authorize**, paste a key.
|
|
85
|
+
|
|
86
|
+
## Flask
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from flask import Flask
|
|
90
|
+
from apikee.flask import init_apikee, apikee_required, require_scope, get_claims
|
|
91
|
+
|
|
92
|
+
app = Flask(__name__)
|
|
93
|
+
init_apikee(app) # reads APIKEE_SECRET — done
|
|
94
|
+
|
|
95
|
+
@app.get("/data")
|
|
96
|
+
@apikee_required
|
|
97
|
+
def data():
|
|
98
|
+
return {"tenant": get_claims().tenant}
|
|
99
|
+
|
|
100
|
+
@app.delete("/admin")
|
|
101
|
+
@require_scope("admin")
|
|
102
|
+
def admin(): ...
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Any ASGI
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from apikee import Apikee
|
|
109
|
+
|
|
110
|
+
apikee = Apikee()
|
|
111
|
+
app.add_middleware(apikee.middleware) # claims at request.state.apikee
|
|
112
|
+
|
|
113
|
+
# Or inline, no middleware:
|
|
114
|
+
claims = apikee.protect(request.headers.get("x-api-key"))
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Key rotation (zero downtime)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
export APIKEE_SECRET=new-secret # new keys signed with this
|
|
121
|
+
# Old keys still validate during the rotation window — pass both to Apikee():
|
|
122
|
+
```
|
|
123
|
+
```python
|
|
124
|
+
apikee = Apikee(secrets=["new-secret", "old-secret"])
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Environment Variables (.env)
|
|
128
|
+
|
|
129
|
+
Python frameworks (FastAPI, Flask, Starlette/ASGI) use the same variables.
|
|
130
|
+
|
|
131
|
+
Required:
|
|
132
|
+
|
|
133
|
+
```env
|
|
134
|
+
APIKEE_SECRET=replace-with-strong-random-secret
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Optional (server mode — requires a running Apikee instance):
|
|
138
|
+
|
|
139
|
+
```env
|
|
140
|
+
APIKEE_BASE_URL=https://apikee.example.com/api/v1
|
|
141
|
+
APIKEE_SERVER_KEY=sk_...
|
|
142
|
+
APIKEE_PROJECT_ENV=my-api-production
|
|
143
|
+
APIKEE_SERVER_PUBLIC_KEY=base64-x25519-public-key # enables payload encryption
|
|
144
|
+
APIKEE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----..." # enables RSA request signing
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Project structure
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
apikee/ Library source — core + framework modules (FastAPI, Flask, server)
|
|
151
|
+
tests/ Test suite
|
|
152
|
+
examples/ Example apps (FastAPI, Flask, Starlette)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for local setup, branch naming
|
|
158
|
+
conventions, and the release process.
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
[MIT](./LICENSE)
|
|
163
|
+
|
|
164
|
+
## Docs
|
|
165
|
+
|
|
166
|
+
[github.com/apikee-dev](https://github.com/apikee-dev)
|