Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Lint

env:
PYTHON_VERSION: "3.12"

# Report on every PR, including changes outside the Python test paths.
# Required checks need a result even when a PR changes no Python files.
on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: lint-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
ruff:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 1
persist-credentials: false
- name: 🐍 setup python
uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: 🛠️ install deps
run: |
python -m pip install --upgrade pip
pip install uv
uv sync --locked --extra dev
- name: 🧹 ruff check
run: uv run --locked --extra dev ruff check
- name: 🎨 ruff format
run: uv run --locked --extra dev ruff format --check
2 changes: 1 addition & 1 deletion .github/workflows/package-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
run: python -m pip install ".[test]" "twine>=4.0.0"

- name: Run unit tests
run: python -m pytest -q tests/unit
run: python -m pytest -q tests/unit tests/integration/test_all_endpoints.py::TestAllEndpointsMocked

- name: Build distributions
run: hatch build
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ dist
*.dist
*.egg-info
*.cpython-312.pyc
example-socket-export.py
__pycache__/
.coverage
.coverage.*
Expand Down
17 changes: 13 additions & 4 deletions .hooks/sync_version.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
import subprocess
import json
import pathlib
import re
import subprocess
import sys
import urllib.request
import json

VERSION_FILE = pathlib.Path("socketdev/version.py")
PYPROJECT_FILE = pathlib.Path("pyproject.toml")
Expand All @@ -16,6 +16,7 @@
PYPI_PROD_API = "https://pypi.org/pypi/socketdev/json"
PYPI_TEST_API = "https://test.pypi.org/pypi/socketdev/json"


def read_version_from_version_file(path: pathlib.Path) -> str:
content = path.read_text()
match = VERSION_PATTERN.search(content)
Expand All @@ -24,6 +25,7 @@ def read_version_from_version_file(path: pathlib.Path) -> str:
sys.exit(1)
return match.group(1)


def read_version_from_git(path: str) -> str:
try:
output = subprocess.check_output(["git", "show", f"HEAD:{path}"], text=True)
Expand All @@ -34,13 +36,15 @@ def read_version_from_git(path: str) -> str:
except subprocess.CalledProcessError:
return None


def bump_patch_version(version: str) -> str:
if ".dev" in version:
version = version.split(".dev")[0]
parts = version.split(".")
parts[-1] = str(int(parts[-1]) + 1)
return ".".join(parts)


def parse_stable_version(version: str):
if not STABLE_VERSION_PATTERN.fullmatch(version):
return None
Expand Down Expand Up @@ -188,16 +192,21 @@ def main():
inject_version(new_version)
uv_lock_changed = run_uv_lock()
lock_hint = " and uv.lock" if uv_lock_changed else ""
print(f"⚠️ Version {current_version} is already published on PyPI — auto-bumped to {new_version}. Please git add{lock_hint} + commit again.")
print(
f"⚠️ Version {current_version} is already published on PyPI — auto-bumped to {new_version}. Please git add{lock_hint} + commit again."
)
sys.exit(1)

uv_lock_changed = run_uv_lock()
if uv_lock_changed:
print("⚠️ Version already bumped, but uv.lock was out of date and has been updated. Please git add uv.lock + commit again.")
print(
"⚠️ Version already bumped, but uv.lock was out of date and has been updated. Please git add uv.lock + commit again."
)
sys.exit(1)

print("✅ Version already bumped and uv.lock is up to date — proceeding.")
sys.exit(0)


if __name__ == "__main__":
main()
18 changes: 18 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
repos:
- repo: local
hooks:

# Use the project's locked Ruff version, shared with CI and make lint.
- id: ruff-check
name: ruff check
entry: uv run --locked --extra dev ruff check --force-exclude --fix
language: system
types_or: [python, pyi]
require_serial: true

- id: ruff-format
name: ruff format
entry: uv run --locked --extra dev ruff format --force-exclude
language: system
types_or: [python, pyi]
require_serial: true
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 3.6.3

### Changed

- Enforce Ruff linting and formatting in CI and pre-commit, using the locked
development tool version. Add `make lint`, `make lint-fix`, `make format`,
and `make hooks` for contributors.
- Bound function complexity at 12 independent paths and eight arguments, with
explicit exceptions for existing functions and checks for obsolete suppressions.
- Full-scan parameter normalization uses debug logging instead of stdout.
- Refresh mocked endpoint tests for the supported API methods and include them
in the default local and CI test runs.

### Fixed

- Repository updates correctly serialize keyword arguments into the request body.
- Report uploads close files opened from paths after the request, including on
failure. Streams supplied by callers remain open.
- Lazy-file validation remains active under `python -O`.

## 3.6.2

### Fixed: reject retired API credentials before use
Expand Down
39 changes: 29 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,43 @@

## Development setup

Use Python 3.9 or newer. Create and activate a virtual environment, then
install the package with its development and test dependencies:
Use Python 3.10 or newer and install [uv](https://docs.astral.sh/uv/). From the
repository root, install the locked development and test dependencies:

```bash
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev,test]"
uv sync --locked --extra dev --extra test
make hooks
```

Before opening a pull request, run the focused checks for your change. The
complete local check is:
Before opening a pull request, run:

```bash
python -m pytest
hatch build
python -m twine check dist/*
make lint
make test
uv run --locked hatch build
uv run --locked python -m twine check dist/*
```

## Linting and formatting

Ruff checks Python source, tests, hooks, examples, and developer scripts. The
rule set lives in `pyproject.toml`; CI, Make targets, and pre-commit use the same
Ruff version from `uv.lock`.

`make lint-fix` applies safe lint fixes. `make format` formats files with a line
length of 120. Pre-commit applies both to staged Python files. Review and stage
any edits before committing again. CI checks the full repository on every pull
request and push to `main`.

Functions are limited to cyclomatic complexity 12 and eight arguments. Existing
over-limit functions carry explicit suppressions; split new functions that exceed
the limits. `RUF100` rejects suppressions that become unnecessary. Avoid running
`ruff check --fix` with a narrow `--select` that includes `RUF100`, because it
can remove markers for rules outside that selection.

Integration tests requiring live credentials are opt-in; see
[tests/README.md](tests/README.md). The default `make test` runs unit tests and mocked endpoint tests.

## Pull request validation

The `Package Check` workflow runs automatically for pull requests. It runs the
Expand Down
20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.PHONY: lint lint-fix format format-check hooks test

lint:
uv run --locked --extra dev ruff check
uv run --locked --extra dev ruff format --check

lint-fix:
uv run --locked --extra dev ruff check --fix

format:
uv run --locked --extra dev ruff format

format-check:
uv run --locked --extra dev ruff format --check

hooks:
uv run --locked --extra dev pre-commit install

test:
uv run --locked --extra test pytest tests/unit tests/integration/test_all_endpoints.py::TestAllEndpointsMocked
15 changes: 9 additions & 6 deletions example-socket-export.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import json
import os
import logging
import os
import sys

from socketdev import socketdev

logging.basicConfig(level=logging.INFO)


Expand All @@ -11,13 +14,13 @@
if len(orgs) > 0:
org_id = None
org_slug = None
for org_key in orgs['organizations']:
org = orgs['organizations'][org_key]
for org_key in orgs["organizations"]:
org = orgs["organizations"][org_key]
org_id = org_key
org_slug = org['slug']
org_slug = org["slug"]
else:
print("Something went wrong with getting org info")
exit(1)
sys.exit(1)
per_page = 100
response = sdk.repos.get(org_slug, per_page=per_page)
next_page = response.get("nextPage")
Expand Down Expand Up @@ -47,7 +50,7 @@
"pull_request_url": full_scan_metadata.get("pull_request_url"),
"committers": full_scan_metadata.get("committers"),
"created_at": full_scan_metadata.get("created_at"),
"results": sdk.fullscans.stream(org_slug=org_slug, full_scan_id=head_full_scan_id) or None
"results": sdk.fullscans.stream(org_slug=org_slug, full_scan_id=head_full_scan_id) or None,
}
socket_results[head_full_scan_id] = full_scan_result

Expand Down
Loading
Loading