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.
@@ -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,13 @@
1
+ .venv/
2
+ __pycache__/
3
+ dist/
4
+ *.egg-info/
5
+ .pytest_cache/
6
+ *.log
7
+ .DS_Store
8
+
9
+ # Never commit local env or key material
10
+ .env
11
+ .env.*
12
+ *.pem
13
+ *.key
@@ -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.