smartlyq 0.1.2__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.
- smartlyq-0.1.2/.githooks/pre-commit +35 -0
- smartlyq-0.1.2/.github/workflows/ci.yml +26 -0
- smartlyq-0.1.2/.github/workflows/generate.yml +141 -0
- smartlyq-0.1.2/.github/workflows/secret-scan.yml +26 -0
- smartlyq-0.1.2/.gitignore +13 -0
- smartlyq-0.1.2/.gitleaks.toml +37 -0
- smartlyq-0.1.2/CONTRIBUTING.md +31 -0
- smartlyq-0.1.2/LICENSE +21 -0
- smartlyq-0.1.2/PKG-INFO +418 -0
- smartlyq-0.1.2/README.md +399 -0
- smartlyq-0.1.2/openapi.json +16688 -0
- smartlyq-0.1.2/pyproject.toml +34 -0
- smartlyq-0.1.2/scripts/generate_client.py +94 -0
- smartlyq-0.1.2/scripts/generate_readme.py +41 -0
- smartlyq-0.1.2/scripts/generate_tests.py +64 -0
- smartlyq-0.1.2/scripts/model.py +156 -0
- smartlyq-0.1.2/smartlyq/__init__.py +60 -0
- smartlyq-0.1.2/smartlyq/_core.py +147 -0
- smartlyq-0.1.2/smartlyq/_version.py +1 -0
- smartlyq-0.1.2/smartlyq/resources.py +908 -0
- smartlyq-0.1.2/tests/test_core.py +100 -0
- smartlyq-0.1.2/tests/test_endpoints_gen.py +1076 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Pre-commit secret scan for this PUBLIC repo.
|
|
3
|
+
#
|
|
4
|
+
# Enable once per clone:
|
|
5
|
+
# git config core.hooksPath .githooks
|
|
6
|
+
#
|
|
7
|
+
# Uses gitleaks when installed (full ruleset); otherwise falls back to a
|
|
8
|
+
# lightweight grep so the gate still works without extra tooling.
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
if command -v gitleaks >/dev/null 2>&1; then
|
|
12
|
+
if ! gitleaks protect --staged --redact --no-banner --config .gitleaks.toml; then
|
|
13
|
+
echo ""
|
|
14
|
+
echo "✖ gitleaks flagged a potential secret in your staged changes. Commit blocked."
|
|
15
|
+
echo " Remove the value (use a placeholder like YOUR_API_KEY) and re-commit."
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
exit 0
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# --- Fallback: grep staged additions for high-signal secret patterns ---------
|
|
22
|
+
staged="$(git diff --cached --name-only --diff-filter=ACM)"
|
|
23
|
+
[ -z "$staged" ] && exit 0
|
|
24
|
+
|
|
25
|
+
patterns='sqk_(live|test)_[A-Za-z0-9]{12,}|AKIA[0-9A-Z]{16}|-----BEGIN [A-Z ]*PRIVATE KEY-----|xox[baprs]-[0-9A-Za-z-]{10,}|gh[pousr]_[0-9A-Za-z]{30,}|AIza[0-9A-Za-z_-]{30,}'
|
|
26
|
+
allow='x{8,}|YOUR_|example|placeholder|redacted|changeme'
|
|
27
|
+
|
|
28
|
+
hits="$(git diff --cached -U0 -- $staged | grep '^+' | grep -vE '^\+\+\+' | grep -EI "$patterns" | grep -viE "$allow" || true)"
|
|
29
|
+
if [ -n "$hits" ]; then
|
|
30
|
+
echo "✖ Potential secret detected in staged changes (install gitleaks for a full scan):"
|
|
31
|
+
echo "$hits"
|
|
32
|
+
echo "Commit blocked. Replace the value with a placeholder and re-commit."
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
exit 0
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Test (Python ${{ matrix.python }})
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python: ['3.9', '3.12']
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python }}
|
|
21
|
+
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: pip install httpx pytest
|
|
24
|
+
|
|
25
|
+
- name: Run tests
|
|
26
|
+
run: python -m pytest -q
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
name: Regenerate
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Fired by the docs repository when openapi.json changes
|
|
5
|
+
repository_dispatch:
|
|
6
|
+
types: [openapi-updated]
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
force_publish:
|
|
10
|
+
description: 'Bump and publish even if the spec is unchanged'
|
|
11
|
+
type: boolean
|
|
12
|
+
default: false
|
|
13
|
+
schedule:
|
|
14
|
+
# Daily safety net in case a dispatch is missed
|
|
15
|
+
- cron: '35 4 * * *'
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: regenerate-sdk
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
generate:
|
|
23
|
+
name: Regenerate from OpenAPI
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
permissions:
|
|
26
|
+
contents: write
|
|
27
|
+
# Lets PyPI verify publishes via Trusted Publishing (OIDC) - no token needed
|
|
28
|
+
id-token: write
|
|
29
|
+
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout repository
|
|
32
|
+
uses: actions/checkout@v4
|
|
33
|
+
with:
|
|
34
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
35
|
+
fetch-depth: 0
|
|
36
|
+
|
|
37
|
+
- name: Setup Python
|
|
38
|
+
uses: actions/setup-python@v5
|
|
39
|
+
with:
|
|
40
|
+
python-version: '3.12'
|
|
41
|
+
|
|
42
|
+
- name: Install dependencies
|
|
43
|
+
run: pip install httpx pytest build
|
|
44
|
+
|
|
45
|
+
- name: Fetch latest OpenAPI spec
|
|
46
|
+
run: curl -f --retry 5 --retry-delay 2 --retry-all-errors --max-time 60 -o openapi.json https://docs.smartlyq.com/openapi.json
|
|
47
|
+
|
|
48
|
+
- name: Generate SDK
|
|
49
|
+
run: python scripts/generate_client.py
|
|
50
|
+
|
|
51
|
+
- name: Generate README reference
|
|
52
|
+
run: python scripts/generate_readme.py
|
|
53
|
+
|
|
54
|
+
- name: Generate endpoint tests
|
|
55
|
+
run: python scripts/generate_tests.py
|
|
56
|
+
|
|
57
|
+
- name: Run tests
|
|
58
|
+
run: python -m pytest -q
|
|
59
|
+
|
|
60
|
+
- name: Check for changes
|
|
61
|
+
id: changes
|
|
62
|
+
run: |
|
|
63
|
+
git add -A
|
|
64
|
+
if ! git diff --staged --quiet || [ "${{ inputs.force_publish }}" = "true" ]; then
|
|
65
|
+
echo "has_changes=true" >> $GITHUB_OUTPUT
|
|
66
|
+
else
|
|
67
|
+
echo "has_changes=false" >> $GITHUB_OUTPUT
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
- name: Bump version and commit
|
|
71
|
+
if: steps.changes.outputs.has_changes == 'true'
|
|
72
|
+
run: |
|
|
73
|
+
git config user.name "github-actions[bot]"
|
|
74
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
75
|
+
|
|
76
|
+
python - <<'EOF'
|
|
77
|
+
import re
|
|
78
|
+
path = "smartlyq/_version.py"
|
|
79
|
+
src = open(path).read()
|
|
80
|
+
m = re.search(r'"(\d+)\.(\d+)\.(\d+)"', src)
|
|
81
|
+
major, minor, patch = map(int, m.groups())
|
|
82
|
+
open(path, "w").write(f'__version__ = "{major}.{minor}.{patch + 1}"\n')
|
|
83
|
+
EOF
|
|
84
|
+
|
|
85
|
+
NEW_VERSION=$(python -c "import re;print(re.search(r'\"(.+)\"', open('smartlyq/_version.py').read()).group(1))")
|
|
86
|
+
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
|
|
87
|
+
|
|
88
|
+
git add -A
|
|
89
|
+
git commit -m "chore: regenerate from OpenAPI spec
|
|
90
|
+
|
|
91
|
+
Auto-generated SDK update (v$NEW_VERSION)"
|
|
92
|
+
|
|
93
|
+
# Retry with rebase to survive concurrent dispatches
|
|
94
|
+
for attempt in 1 2 3; do
|
|
95
|
+
if git push; then break; fi
|
|
96
|
+
echo "Push attempt $attempt failed; rebasing and retrying..."
|
|
97
|
+
git pull --rebase origin main
|
|
98
|
+
sleep $((attempt * 5))
|
|
99
|
+
done
|
|
100
|
+
|
|
101
|
+
# Runs unconditionally so a version that never reached PyPI publishes on
|
|
102
|
+
# the next run; already-published versions skip cleanly.
|
|
103
|
+
- name: Check if version already published
|
|
104
|
+
id: check_published
|
|
105
|
+
run: |
|
|
106
|
+
CURRENT_VERSION=$(python -c "import re;print(re.search(r'\"(.+)\"', open('smartlyq/_version.py').read()).group(1))")
|
|
107
|
+
echo "version=${CURRENT_VERSION}" >> $GITHUB_OUTPUT
|
|
108
|
+
if curl -sf "https://pypi.org/pypi/smartlyq/${CURRENT_VERSION}/json" >/dev/null; then
|
|
109
|
+
echo "skip=true" >> $GITHUB_OUTPUT
|
|
110
|
+
echo "Version ${CURRENT_VERSION} already on PyPI, skipping publish."
|
|
111
|
+
else
|
|
112
|
+
echo "skip=false" >> $GITHUB_OUTPUT
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
- name: Build distribution
|
|
116
|
+
if: steps.check_published.outputs.skip != 'true'
|
|
117
|
+
run: python -m build
|
|
118
|
+
|
|
119
|
+
# Publishes via PyPI Trusted Publishing (OIDC) - no token secret involved.
|
|
120
|
+
# NOTE: no continue-on-error. A failed publish must fail the run loudly.
|
|
121
|
+
- name: Publish to PyPI
|
|
122
|
+
if: steps.check_published.outputs.skip != 'true'
|
|
123
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
124
|
+
|
|
125
|
+
- name: Create GitHub Release
|
|
126
|
+
if: steps.check_published.outputs.skip != 'true'
|
|
127
|
+
uses: softprops/action-gh-release@v1
|
|
128
|
+
with:
|
|
129
|
+
tag_name: v${{ steps.check_published.outputs.version }}
|
|
130
|
+
name: v${{ steps.check_published.outputs.version }}
|
|
131
|
+
generate_release_notes: true
|
|
132
|
+
body: |
|
|
133
|
+
## Auto-generated SDK update
|
|
134
|
+
|
|
135
|
+
This release was generated from the latest OpenAPI spec.
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install smartlyq==${{ steps.check_published.outputs.version }}
|
|
139
|
+
```
|
|
140
|
+
env:
|
|
141
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Secret scan
|
|
2
|
+
|
|
3
|
+
# Blocks secrets from landing in this public repo. Runs on every push and PR,
|
|
4
|
+
# scanning the full history of the pushed range against .gitleaks.toml.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [main]
|
|
8
|
+
pull_request:
|
|
9
|
+
workflow_dispatch: {}
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
gitleaks:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0 # full history so newly-pushed commits are scanned
|
|
21
|
+
# Runs the gitleaks CLI directly: the wrapper action requires a license
|
|
22
|
+
# key on organization-owned repos; the CLI itself is free (MIT).
|
|
23
|
+
- name: Run gitleaks
|
|
24
|
+
run: |
|
|
25
|
+
curl -sSfL https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz | tar -xz gitleaks
|
|
26
|
+
./gitleaks git --config .gitleaks.toml --redact --no-banner --verbose .
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Secret-scan config for this PUBLIC repo (used by the pre-commit hook and CI).
|
|
2
|
+
# Extends gitleaks' built-in ruleset (AWS keys, private keys, GitHub/Slack/Stripe
|
|
3
|
+
# tokens, generic high-entropy strings, etc.) with SmartlyQ-specific rules.
|
|
4
|
+
title = "SmartlyQ public-repo secret scan"
|
|
5
|
+
|
|
6
|
+
[extend]
|
|
7
|
+
useDefault = true
|
|
8
|
+
|
|
9
|
+
# --- SmartlyQ API keys -------------------------------------------------------
|
|
10
|
+
[[rules]]
|
|
11
|
+
id = "smartlyq-api-key"
|
|
12
|
+
description = "SmartlyQ API key (sqk_live_ / sqk_test_)"
|
|
13
|
+
regex = '''sqk_(live|test)_[A-Za-z0-9]{12,}'''
|
|
14
|
+
keywords = ["sqk_live_", "sqk_test_"]
|
|
15
|
+
[rules.allowlist]
|
|
16
|
+
description = "Documentation placeholders (e.g. sqk_live_xxxxxxxxxxxx)"
|
|
17
|
+
regexes = ['''sqk_(live|test)_[xX]+''']
|
|
18
|
+
|
|
19
|
+
# --- Internal-only hostnames -------------------------------------------------
|
|
20
|
+
# Catch internal/staging hosts. Public docs should only reference the public
|
|
21
|
+
# *.smartlyq.com surface. Tune the allowlist if a new public host is added.
|
|
22
|
+
[[rules]]
|
|
23
|
+
id = "internal-host"
|
|
24
|
+
description = "Possible internal/staging host or raw IP in a public file"
|
|
25
|
+
regex = '''(?i)\b((staging|internal|admin|dev|db|sql|redis|mariadb)[-.][a-z0-9.-]*smartlyq\.com|(\d{1,3}\.){3}\d{1,3}:\d{2,5})\b'''
|
|
26
|
+
keywords = ["staging", "internal", "admin", "mariadb"]
|
|
27
|
+
|
|
28
|
+
# --- Global allowlist for obvious doc placeholders ---------------------------
|
|
29
|
+
[allowlist]
|
|
30
|
+
description = "Placeholders that are never real secrets"
|
|
31
|
+
regexTarget = "line"
|
|
32
|
+
regexes = [
|
|
33
|
+
'''(?i)YOUR_(API_KEY|TOKEN|SECRET)''',
|
|
34
|
+
'''(?i)\b(example|placeholder|changeme|redacted)\b''',
|
|
35
|
+
'''x{8,}''',
|
|
36
|
+
'''whsec_a1b2c3d4e5f6''',
|
|
37
|
+
]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in the SmartlyQ Python SDK!
|
|
4
|
+
|
|
5
|
+
## How this repo works
|
|
6
|
+
|
|
7
|
+
Most of this SDK is **generated** from the [SmartlyQ OpenAPI spec](https://docs.smartlyq.com):
|
|
8
|
+
|
|
9
|
+
- `smartlyq/resources.py` - emitted by `scripts/generate_client.py`. Never edit by hand.
|
|
10
|
+
- `tests/test_endpoints_gen.py` - emitted by `scripts/generate_tests.py`. Never edit by hand.
|
|
11
|
+
- The README's API Reference section - emitted by `scripts/generate_readme.py`.
|
|
12
|
+
|
|
13
|
+
Hand-written code lives in `smartlyq/_core.py`, `smartlyq/__init__.py`, `scripts/`, and `tests/test_core.py`. Fixes to generated output belong in the generator scripts, or in the OpenAPI spec itself.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install httpx pytest build
|
|
17
|
+
python scripts/generate_client.py && python scripts/generate_readme.py && python scripts/generate_tests.py
|
|
18
|
+
python -m pytest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Never commit secrets
|
|
22
|
+
|
|
23
|
+
This is a **public** repository. Never commit real API keys (`sqk_live_...` / `sqk_test_...`), credentials, tokens, internal hostnames, or customer data. Use placeholders like `sqk_live_xxxxxxxxxxxx` or `YOUR_API_KEY` in examples.
|
|
24
|
+
|
|
25
|
+
Enable the local pre-commit scan once per clone:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git config core.hooksPath .githooks
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
CI also runs a gitleaks scan on every push and pull request. If you believe a secret has been exposed, rotate it immediately in your Developer Dashboard.
|
smartlyq-0.1.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SmartlyQ
|
|
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.
|