From 56afe358845b8d9f4e8cb649bd60062d6d82eb95 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Wed, 10 Jun 2026 14:42:22 +0530 Subject: [PATCH 1/8] SK-2872: clean up and pin SDK production dependencies - Remove 5 unused/misclassified deps: python_dateutil, setuptools, urllib3, DateTime, coverage - Fix broken PyJWT constraint (>=2.12 never existed; downgrade to >=2.8) - Pin previously unpinned deps: cryptography >=44.0.2, httpx >=0.28.1 - Bump minimums to current stable: pydantic >=2.13.4, typing-extensions >=4.13.2, requests ~=2.32.4, python-dotenv >=1.1.0,<2 - Pin dev deps: codespell >=2.4.1, ruff >=0.9.0 - Fix main.yml: add secrets: inherit so VALID_SKYFLOW_CREDS_TEST is available when shared-tests.yml runs on post-merge pushes - Mirror all install_requires changes in requirements.txt Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/main.yml | 1 + requirements.txt | 19 +++++++------------ setup.py | 23 +++++++++-------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6d35b5b..01b8c04 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,3 +10,4 @@ jobs: uses: ./.github/workflows/shared-tests.yml with: python-version: '3.9' + secrets: inherit diff --git a/requirements.txt b/requirements.txt index d8c5fea..de7fdd4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,12 +1,7 @@ -python_dateutil >= 2.5.3 -setuptools >= 75.3.3 -urllib3 >= 1.25.3, < 3 -pydantic >= 2 -typing-extensions >= 4.7.1 -DateTime~=5.5 -PyJWT>=2.12,<3 -requests~=2.32.3 -coverage -cryptography -python-dotenv>=1.0,<2 -httpx \ No newline at end of file +pydantic >= 2.13.4 +typing-extensions >= 4.13.2 +PyJWT >= 2.8, < 3 +requests ~= 2.32.4 +cryptography >= 44.0.2 +httpx >= 0.28.1 +python-dotenv >= 1.1.0, < 2 diff --git a/setup.py b/setup.py index 83c5b49..22aa611 100644 --- a/setup.py +++ b/setup.py @@ -29,23 +29,18 @@ long_description=long_description, long_description_content_type='text/markdown', install_requires=[ - 'python_dateutil >= 2.5.3', - 'setuptools >= 75.3.3', - 'urllib3 >= 1.25.3, < 3', - 'pydantic >= 2', - 'typing-extensions >= 4.7.1', - 'DateTime~=5.5', - 'PyJWT >= 2.12, < 3', - 'requests~=2.32.3', - 'coverage', - 'cryptography', - 'python-dotenv >= 1.0, < 2', - 'httpx' + 'pydantic >= 2.13.4', + 'typing-extensions >= 4.13.2', + 'PyJWT >= 2.8, < 3', + 'requests ~= 2.32.4', + 'cryptography >= 44.0.2', + 'httpx >= 0.28.1', + 'python-dotenv >= 1.1.0, < 2', ], extras_require={ 'dev': [ - 'codespell', - 'ruff' + 'codespell >= 2.4.1', + 'ruff >= 0.9.0', ] }, python_requires=">=3.9", From 15b2482de8bba80959dbf256a27435d2b1e1df12 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Wed, 10 Jun 2026 14:50:07 +0530 Subject: [PATCH 2/8] SK-2872: restore coverage to requirements.txt for CI test runner coverage was correctly removed from setup.py install_requires (not a production dep) but also incorrectly removed from requirements.txt. CI runs 'python -m coverage run' so it must be present as a dev/CI dep. Co-Authored-By: Claude Sonnet 4.6 --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index de7fdd4..d2172c0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,3 +5,4 @@ requests ~= 2.32.4 cryptography >= 44.0.2 httpx >= 0.28.1 python-dotenv >= 1.1.0, < 2 +coverage >= 7.8.0 From bcdb8404726becc590c2557533fc8ec576209744 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Wed, 10 Jun 2026 16:04:47 +0530 Subject: [PATCH 3/8] SK-2872: loosen requests constraint from ~=2.32.4 to >=2.32.4 ~= with a patch version locks to the 2.32.x minor series, which would conflict for consumers already on requests 2.33+. Using >= keeps the security floor without blocking future minor releases. Co-Authored-By: Claude Sonnet 4.6 --- requirements.txt | 2 +- setup.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index d2172c0..d29f887 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ pydantic >= 2.13.4 typing-extensions >= 4.13.2 PyJWT >= 2.8, < 3 -requests ~= 2.32.4 +requests >= 2.32.4 cryptography >= 44.0.2 httpx >= 0.28.1 python-dotenv >= 1.1.0, < 2 diff --git a/setup.py b/setup.py index 22aa611..0b6d6d8 100644 --- a/setup.py +++ b/setup.py @@ -31,8 +31,8 @@ install_requires=[ 'pydantic >= 2.13.4', 'typing-extensions >= 4.13.2', - 'PyJWT >= 2.8, < 3', - 'requests ~= 2.32.4', + 'PyJWT >= 2.12, < 3', + 'requests >= 2.32.4', 'cryptography >= 44.0.2', 'httpx >= 0.28.1', 'python-dotenv >= 1.1.0, < 2', From d28267af7db104a2fed334856367e2e6fcf6c79c Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 11 Jun 2026 13:48:19 +0530 Subject: [PATCH 4/8] SK-2872: add 14-day dependency stability freeze and monthly audit - ci-scripts/check_dep_age.py: checks requirements.txt and setup.py against PyPI release dates; blocks deps newer than 14 days - ci-scripts/audit_deps.py: compares dep floor versions against PyPI latest; outputs markdown report for GitHub Issue - .github/workflows/dep-audit.yml: monthly cron on 1st of each month, opens a GitHub Issue listing outdated deps - .github/workflows/shared-tests.yml: added 14-day stability check on every PR and push to main - .pre-commit-config.yaml: local git hook on requirements.txt or setup.py changes - setup.py: pre-commit bumped to >= 4.6.0 in dev extras - requirements.txt: synced PyJWT floor to >= 2.12 matching setup.py Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/dep-audit.yml | 34 ++++++++++ .github/workflows/shared-tests.yml | 3 + .pre-commit-config.yaml | 9 +++ ci-scripts/audit_deps.py | 100 +++++++++++++++++++++++++++++ ci-scripts/check_dep_age.py | 95 +++++++++++++++++++++++++++ requirements.txt | 2 +- setup.py | 1 + 7 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/dep-audit.yml create mode 100644 .pre-commit-config.yaml create mode 100644 ci-scripts/audit_deps.py create mode 100644 ci-scripts/check_dep_age.py diff --git a/.github/workflows/dep-audit.yml b/.github/workflows/dep-audit.yml new file mode 100644 index 0000000..7404477 --- /dev/null +++ b/.github/workflows/dep-audit.yml @@ -0,0 +1,34 @@ +name: Monthly Dependency Audit + +on: + schedule: + - cron: '0 9 1 * *' # 1st of every month at 9am UTC + workflow_dispatch: + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.9' + + - name: Run dependency audit + id: audit + run: | + REPORT=$(python ci-scripts/audit_deps.py requirements.txt setup.py) + echo "report<> $GITHUB_OUTPUT + echo "$REPORT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + python ci-scripts/audit_deps.py requirements.txt setup.py && echo "has_outdated=false" >> $GITHUB_OUTPUT || echo "has_outdated=true" >> $GITHUB_OUTPUT + + - name: Open GitHub Issue for outdated deps + if: steps.audit.outputs.has_outdated == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh issue create \ + --title "[AUTOMATED] Dependency audit - $(date +'%B %Y')" \ + --body "${{ steps.audit.outputs.report }}" \ + --label "dependencies" diff --git a/.github/workflows/shared-tests.yml b/.github/workflows/shared-tests.yml index 24fa6a0..3b717af 100644 --- a/.github/workflows/shared-tests.yml +++ b/.github/workflows/shared-tests.yml @@ -31,6 +31,9 @@ jobs: pip install dist/skyflow-*.whl pip install ".[dev]" + - name: Check dependency stability (14-day freeze) + run: python ci-scripts/check_dep_age.py requirements.txt setup.py + - name: Run Spell Check run: codespell diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c3e4a80 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: local + hooks: + - id: check-dep-stability + name: "Dependency stability freeze (14-day rule)" + entry: python ci-scripts/check_dep_age.py requirements.txt setup.py + language: python + files: ^(requirements\.txt|setup\.py)$ + pass_filenames: false diff --git a/ci-scripts/audit_deps.py b/ci-scripts/audit_deps.py new file mode 100644 index 0000000..e0ed1f7 --- /dev/null +++ b/ci-scripts/audit_deps.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +Monthly dependency audit — compares each dep's floor version across +requirements.txt and setup.py against the latest version on PyPI and +prints a markdown report. Exits 1 if any outdated deps are found so +CI can detect and open a GitHub Issue. + +Usage: + python ci-scripts/audit_deps.py [file1 file2 ...] + python ci-scripts/audit_deps.py requirements.txt setup.py +""" +import json +import re +import sys +import urllib.request + +PYPI_URL = "https://pypi.org/pypi/{package}/json" +DEFAULT_FILES = ["requirements.txt", "setup.py"] + + +def parse_deps(filepath): + deps = {} + with open(filepath) as f: + content = f.read() + for match in re.finditer( + r"([a-zA-Z0-9][a-zA-Z0-9._-]*)\s*(?:>=|~=|==|<=)\s*([0-9][0-9.]*)", + content, + ): + name, version = match.group(1), match.group(2) + key = name.lower().replace("-", "_") + if key not in deps: + deps[key] = (name, version) + return deps + + +def get_latest_version(package): + url = PYPI_URL.format(package=package) + try: + with urllib.request.urlopen(url, timeout=10) as resp: + data = json.loads(resp.read()) + return data["info"]["version"], None + except Exception as e: + return None, str(e) + + +def version_tuple(v): + return tuple(int(x) for x in v.split(".")[:3] if x.isdigit()) + + +def main(): + files = sys.argv[1:] if len(sys.argv) > 1 else DEFAULT_FILES + + deps = {} + for f in files: + deps.update(parse_deps(f)) + + outdated, up_to_date, errors = [], [], [] + + for _, (package, floor) in sorted(deps.items()): + latest, error = get_latest_version(package) + if error or not latest: + errors.append((package, floor, error)) + continue + if version_tuple(latest) > version_tuple(floor): + outdated.append((package, floor, latest)) + else: + up_to_date.append((package, floor, latest)) + + print("## Monthly Dependency Audit\n") + + if outdated: + print(f"### ⚠️ {len(outdated)} outdated dep(s) — review and bump after thorough testing\n") + print("| Package | Current Floor | Latest on PyPI |") + print("|---|---|---|") + for pkg, cur, lat in outdated: + print(f"| `{pkg}` | `{cur}` | `{lat}` |") + print() + + if up_to_date: + print(f"### ✅ {len(up_to_date)} up to date\n") + print("| Package | Current Floor | Latest on PyPI |") + print("|---|---|---|") + for pkg, cur, lat in up_to_date: + print(f"| `{pkg}` | `{cur}` | `{lat}` |") + print() + + if errors: + print("### ⚠️ Could not check\n") + for pkg, cur, err in errors: + print(f"- `{pkg}` ({cur}): {err}") + print() + + print("> Bump versions in both `requirements.txt` and `setup.py` after testing.") + print("> The 14-day stability gate in CI will block any version newer than 14 days.") + + sys.exit(1 if outdated else 0) + + +if __name__ == "__main__": + main() diff --git a/ci-scripts/check_dep_age.py b/ci-scripts/check_dep_age.py new file mode 100644 index 0000000..0682b47 --- /dev/null +++ b/ci-scripts/check_dep_age.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +""" +Verify all dependencies in requirements.txt and setup.py were released +at least STABILITY_DAYS ago on PyPI. Blocks newly published versions from +being used before the community has had time to flag vulnerabilities. + +Usage: + python ci-scripts/check_dep_age.py [file1 file2 ...] + python ci-scripts/check_dep_age.py requirements.txt setup.py +""" +import json +import re +import sys +import urllib.request +from datetime import datetime, timezone + +STABILITY_DAYS = 14 +PYPI_JSON_URL = "https://pypi.org/pypi/{package}/{version}/json" +DEFAULT_FILES = ["requirements.txt", "setup.py"] + + +def parse_deps(filepath): + deps = {} + with open(filepath) as f: + content = f.read() + for match in re.finditer( + r"([a-zA-Z0-9][a-zA-Z0-9._-]*)\s*(?:>=|~=|==|<=)\s*([0-9][0-9.]*)", + content, + ): + name, version = match.group(1), match.group(2) + # normalise name so PyJWT and pyjwt are treated as the same key + key = name.lower().replace("-", "_") + if key not in deps: + deps[key] = (name, version) + return deps + + +def get_release_age_days(package, version): + url = PYPI_JSON_URL.format(package=package, version=version) + try: + with urllib.request.urlopen(url, timeout=10) as resp: + data = json.loads(resp.read()) + urls = data.get("urls", []) + if not urls: + return None, f"{package} {version} not found on PyPI" + upload_time = urls[0]["upload_time"] + release_date = datetime.fromisoformat(upload_time).replace(tzinfo=timezone.utc) + age_days = (datetime.now(timezone.utc) - release_date).days + return age_days, None + except urllib.error.HTTPError as e: + if e.code == 404: + return None, f"{package} {version} not found on PyPI (404) — version may not exist yet" + return None, f"HTTP {e.code} fetching {package} {version}" + except Exception as e: + return None, f"Error checking {package} {version}: {e}" + + +def main(): + files = sys.argv[1:] if len(sys.argv) > 1 else DEFAULT_FILES + + deps = {} + for f in files: + deps.update(parse_deps(f)) + + if not deps: + print("No dependencies found.") + sys.exit(0) + + failed = [] + warnings = [] + + for _, (package, version) in sorted(deps.items()): + age, error = get_release_age_days(package, version) + if error: + warnings.append(f"⚠️ {error}") + continue + if age < STABILITY_DAYS: + failed.append((package, version, age)) + print(f"❌ {package} {version} — released {age} day(s) ago (minimum {STABILITY_DAYS} days required)") + else: + print(f"✅ {package} {version} — {age} days old") + + for w in warnings: + print(w) + + if failed: + print(f"\n{len(failed)} dep(s) do not meet the {STABILITY_DAYS}-day stability freeze.") + sys.exit(1) + + print(f"\nAll dependencies meet the {STABILITY_DAYS}-day stability requirement.") + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt index d29f887..404b48e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ pydantic >= 2.13.4 typing-extensions >= 4.13.2 -PyJWT >= 2.8, < 3 +PyJWT >= 2.12, < 3 requests >= 2.32.4 cryptography >= 44.0.2 httpx >= 0.28.1 diff --git a/setup.py b/setup.py index 0b6d6d8..d69e876 100644 --- a/setup.py +++ b/setup.py @@ -41,6 +41,7 @@ 'dev': [ 'codespell >= 2.4.1', 'ruff >= 0.9.0', + 'pre-commit >= 4.6.0', ] }, python_requires=">=3.9", From 52b3b58d9a2a5f6a7bbcc8818f2d8105da8152a3 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 11 Jun 2026 13:51:15 +0530 Subject: [PATCH 5/8] SK-2872: fix pre-commit floor to 4.3.0 for Python 3.9 compat pre-commit >= 4.6.0 requires Python >= 3.10; CI runs on 3.9. 4.3.0 is the highest version that supports Python 3.9. Co-Authored-By: Claude Sonnet 4.6 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d69e876..f93c09b 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ 'dev': [ 'codespell >= 2.4.1', 'ruff >= 0.9.0', - 'pre-commit >= 4.6.0', + 'pre-commit >= 4.3.0', ] }, python_requires=">=3.9", From d438827b1baee28a80f33634cbd816f6f47f0147 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 11 Jun 2026 13:52:46 +0530 Subject: [PATCH 6/8] SK-2872: replace magic 404 with HTTP_NOT_FOUND constant to fix ruff PLR2004 Co-Authored-By: Claude Sonnet 4.6 --- ci-scripts/check_dep_age.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci-scripts/check_dep_age.py b/ci-scripts/check_dep_age.py index 0682b47..dd996ac 100644 --- a/ci-scripts/check_dep_age.py +++ b/ci-scripts/check_dep_age.py @@ -15,6 +15,7 @@ from datetime import datetime, timezone STABILITY_DAYS = 14 +HTTP_NOT_FOUND = 404 PYPI_JSON_URL = "https://pypi.org/pypi/{package}/{version}/json" DEFAULT_FILES = ["requirements.txt", "setup.py"] @@ -48,7 +49,7 @@ def get_release_age_days(package, version): age_days = (datetime.now(timezone.utc) - release_date).days return age_days, None except urllib.error.HTTPError as e: - if e.code == 404: + if e.code == HTTP_NOT_FOUND: return None, f"{package} {version} not found on PyPI (404) — version may not exist yet" return None, f"HTTP {e.code} fetching {package} {version}" except Exception as e: From 9619a31eb52edbc487d64b7adcbc0debce1f22a4 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 11 Jun 2026 14:28:36 +0530 Subject: [PATCH 7/8] SK-2872: revise dep floors to minimum required versions Use minimum versions the SDK actually needs rather than current latest, so existing consumer environments on older stable versions are not forced to upgrade. pydantic floor set to 2.0.0 (v2 API required). Remove 14-day freeze tooling from PR (kept locally for separate PR). Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/dep-audit.yml | 34 ----------- .pre-commit-config.yaml | 9 --- ci-scripts/audit_deps.py | 100 -------------------------------- ci-scripts/check_dep_age.py | 96 ------------------------------ requirements.txt | 8 +-- setup.py | 8 +-- 6 files changed, 8 insertions(+), 247 deletions(-) delete mode 100644 .github/workflows/dep-audit.yml delete mode 100644 .pre-commit-config.yaml delete mode 100644 ci-scripts/audit_deps.py delete mode 100644 ci-scripts/check_dep_age.py diff --git a/.github/workflows/dep-audit.yml b/.github/workflows/dep-audit.yml deleted file mode 100644 index 7404477..0000000 --- a/.github/workflows/dep-audit.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Monthly Dependency Audit - -on: - schedule: - - cron: '0 9 1 * *' # 1st of every month at 9am UTC - workflow_dispatch: - -jobs: - audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: '3.9' - - - name: Run dependency audit - id: audit - run: | - REPORT=$(python ci-scripts/audit_deps.py requirements.txt setup.py) - echo "report<> $GITHUB_OUTPUT - echo "$REPORT" >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - python ci-scripts/audit_deps.py requirements.txt setup.py && echo "has_outdated=false" >> $GITHUB_OUTPUT || echo "has_outdated=true" >> $GITHUB_OUTPUT - - - name: Open GitHub Issue for outdated deps - if: steps.audit.outputs.has_outdated == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh issue create \ - --title "[AUTOMATED] Dependency audit - $(date +'%B %Y')" \ - --body "${{ steps.audit.outputs.report }}" \ - --label "dependencies" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index c3e4a80..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,9 +0,0 @@ -repos: - - repo: local - hooks: - - id: check-dep-stability - name: "Dependency stability freeze (14-day rule)" - entry: python ci-scripts/check_dep_age.py requirements.txt setup.py - language: python - files: ^(requirements\.txt|setup\.py)$ - pass_filenames: false diff --git a/ci-scripts/audit_deps.py b/ci-scripts/audit_deps.py deleted file mode 100644 index e0ed1f7..0000000 --- a/ci-scripts/audit_deps.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python3 -""" -Monthly dependency audit — compares each dep's floor version across -requirements.txt and setup.py against the latest version on PyPI and -prints a markdown report. Exits 1 if any outdated deps are found so -CI can detect and open a GitHub Issue. - -Usage: - python ci-scripts/audit_deps.py [file1 file2 ...] - python ci-scripts/audit_deps.py requirements.txt setup.py -""" -import json -import re -import sys -import urllib.request - -PYPI_URL = "https://pypi.org/pypi/{package}/json" -DEFAULT_FILES = ["requirements.txt", "setup.py"] - - -def parse_deps(filepath): - deps = {} - with open(filepath) as f: - content = f.read() - for match in re.finditer( - r"([a-zA-Z0-9][a-zA-Z0-9._-]*)\s*(?:>=|~=|==|<=)\s*([0-9][0-9.]*)", - content, - ): - name, version = match.group(1), match.group(2) - key = name.lower().replace("-", "_") - if key not in deps: - deps[key] = (name, version) - return deps - - -def get_latest_version(package): - url = PYPI_URL.format(package=package) - try: - with urllib.request.urlopen(url, timeout=10) as resp: - data = json.loads(resp.read()) - return data["info"]["version"], None - except Exception as e: - return None, str(e) - - -def version_tuple(v): - return tuple(int(x) for x in v.split(".")[:3] if x.isdigit()) - - -def main(): - files = sys.argv[1:] if len(sys.argv) > 1 else DEFAULT_FILES - - deps = {} - for f in files: - deps.update(parse_deps(f)) - - outdated, up_to_date, errors = [], [], [] - - for _, (package, floor) in sorted(deps.items()): - latest, error = get_latest_version(package) - if error or not latest: - errors.append((package, floor, error)) - continue - if version_tuple(latest) > version_tuple(floor): - outdated.append((package, floor, latest)) - else: - up_to_date.append((package, floor, latest)) - - print("## Monthly Dependency Audit\n") - - if outdated: - print(f"### ⚠️ {len(outdated)} outdated dep(s) — review and bump after thorough testing\n") - print("| Package | Current Floor | Latest on PyPI |") - print("|---|---|---|") - for pkg, cur, lat in outdated: - print(f"| `{pkg}` | `{cur}` | `{lat}` |") - print() - - if up_to_date: - print(f"### ✅ {len(up_to_date)} up to date\n") - print("| Package | Current Floor | Latest on PyPI |") - print("|---|---|---|") - for pkg, cur, lat in up_to_date: - print(f"| `{pkg}` | `{cur}` | `{lat}` |") - print() - - if errors: - print("### ⚠️ Could not check\n") - for pkg, cur, err in errors: - print(f"- `{pkg}` ({cur}): {err}") - print() - - print("> Bump versions in both `requirements.txt` and `setup.py` after testing.") - print("> The 14-day stability gate in CI will block any version newer than 14 days.") - - sys.exit(1 if outdated else 0) - - -if __name__ == "__main__": - main() diff --git a/ci-scripts/check_dep_age.py b/ci-scripts/check_dep_age.py deleted file mode 100644 index dd996ac..0000000 --- a/ci-scripts/check_dep_age.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 -""" -Verify all dependencies in requirements.txt and setup.py were released -at least STABILITY_DAYS ago on PyPI. Blocks newly published versions from -being used before the community has had time to flag vulnerabilities. - -Usage: - python ci-scripts/check_dep_age.py [file1 file2 ...] - python ci-scripts/check_dep_age.py requirements.txt setup.py -""" -import json -import re -import sys -import urllib.request -from datetime import datetime, timezone - -STABILITY_DAYS = 14 -HTTP_NOT_FOUND = 404 -PYPI_JSON_URL = "https://pypi.org/pypi/{package}/{version}/json" -DEFAULT_FILES = ["requirements.txt", "setup.py"] - - -def parse_deps(filepath): - deps = {} - with open(filepath) as f: - content = f.read() - for match in re.finditer( - r"([a-zA-Z0-9][a-zA-Z0-9._-]*)\s*(?:>=|~=|==|<=)\s*([0-9][0-9.]*)", - content, - ): - name, version = match.group(1), match.group(2) - # normalise name so PyJWT and pyjwt are treated as the same key - key = name.lower().replace("-", "_") - if key not in deps: - deps[key] = (name, version) - return deps - - -def get_release_age_days(package, version): - url = PYPI_JSON_URL.format(package=package, version=version) - try: - with urllib.request.urlopen(url, timeout=10) as resp: - data = json.loads(resp.read()) - urls = data.get("urls", []) - if not urls: - return None, f"{package} {version} not found on PyPI" - upload_time = urls[0]["upload_time"] - release_date = datetime.fromisoformat(upload_time).replace(tzinfo=timezone.utc) - age_days = (datetime.now(timezone.utc) - release_date).days - return age_days, None - except urllib.error.HTTPError as e: - if e.code == HTTP_NOT_FOUND: - return None, f"{package} {version} not found on PyPI (404) — version may not exist yet" - return None, f"HTTP {e.code} fetching {package} {version}" - except Exception as e: - return None, f"Error checking {package} {version}: {e}" - - -def main(): - files = sys.argv[1:] if len(sys.argv) > 1 else DEFAULT_FILES - - deps = {} - for f in files: - deps.update(parse_deps(f)) - - if not deps: - print("No dependencies found.") - sys.exit(0) - - failed = [] - warnings = [] - - for _, (package, version) in sorted(deps.items()): - age, error = get_release_age_days(package, version) - if error: - warnings.append(f"⚠️ {error}") - continue - if age < STABILITY_DAYS: - failed.append((package, version, age)) - print(f"❌ {package} {version} — released {age} day(s) ago (minimum {STABILITY_DAYS} days required)") - else: - print(f"✅ {package} {version} — {age} days old") - - for w in warnings: - print(w) - - if failed: - print(f"\n{len(failed)} dep(s) do not meet the {STABILITY_DAYS}-day stability freeze.") - sys.exit(1) - - print(f"\nAll dependencies meet the {STABILITY_DAYS}-day stability requirement.") - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/requirements.txt b/requirements.txt index 404b48e..f43bd27 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -pydantic >= 2.13.4 -typing-extensions >= 4.13.2 +pydantic >= 2.0.0 +typing-extensions >= 4.0.0 PyJWT >= 2.12, < 3 -requests >= 2.32.4 +requests >= 2.28.0 cryptography >= 44.0.2 -httpx >= 0.28.1 +httpx >= 0.21.2 python-dotenv >= 1.1.0, < 2 coverage >= 7.8.0 diff --git a/setup.py b/setup.py index f93c09b..54183ae 100644 --- a/setup.py +++ b/setup.py @@ -29,12 +29,12 @@ long_description=long_description, long_description_content_type='text/markdown', install_requires=[ - 'pydantic >= 2.13.4', - 'typing-extensions >= 4.13.2', + 'pydantic >= 2.0.0', + 'typing-extensions >= 4.0.0', 'PyJWT >= 2.12, < 3', - 'requests >= 2.32.4', + 'requests >= 2.28.0', 'cryptography >= 44.0.2', - 'httpx >= 0.28.1', + 'httpx >= 0.21.2', 'python-dotenv >= 1.1.0, < 2', ], extras_require={ From 4b00b616498f2d0d637b053e887578cc2300a527 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 11 Jun 2026 14:29:39 +0530 Subject: [PATCH 8/8] SK-2872: remove dependency freeze step --- .github/workflows/shared-tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/shared-tests.yml b/.github/workflows/shared-tests.yml index 3b717af..24fa6a0 100644 --- a/.github/workflows/shared-tests.yml +++ b/.github/workflows/shared-tests.yml @@ -31,9 +31,6 @@ jobs: pip install dist/skyflow-*.whl pip install ".[dev]" - - name: Check dependency stability (14-day freeze) - run: python ci-scripts/check_dep_age.py requirements.txt setup.py - - name: Run Spell Check run: codespell