Tags: SocketDev/socket-python-cli
Tags
docs: correct remaining reachability reference gaps (#228) Reachability-reference fixes layered on current main (v2.4.5): - Document the uv + Enterprise-plan prerequisites the CLI enforces before running reachability (exit 3), and that per-ecosystem build toolchains are the analysis engine's runtime check, not a CLI pre-check. - Correct --reach-min-severity values to info/low/moderate/high/critical. - Document --reach-enable-analysis-splitting, --reach-detailed-analysis-log-file, --reach-lazy-mode, --reach-use-only-pregenerated-sboms. - Clarify --only-facts-file submits only the facts file when creating the full scan (no pre-existing scan required). - Note --reach creates a tier-1 full-application scan (scan_type=socket_tier1). Docs-only; the version bump + uv.lock are mandated by the sync-version hook.
Harden dependency review checks across PR types (#224) * ci: report e2e-* checks on fork and Dependabot PRs The e2e job is skipped on PRs that can't access repository secrets (forks and Dependabot). Because it's skipped via a job-level `if`, its matrix never expands, so the required e2e-* check contexts are never created and branch protection waits on them indefinitely, blocking merge. Add an e2e-bypass job whose `if` is the exact negation of the e2e job's run condition. It emits the same e2e-* check names with a passing status for fork/Dependabot PRs, satisfying branch protection without running the real tests. The two jobs are mutually exclusive and exhaustive: every PR runs exactly one. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * ci: add dependency-review-gate aggregator check The Socket Firewall enterprise smoke job is the most meaningful supply-chain check for maintainer-added dependencies, but it can't be required directly: it's conditional (per-manifest, and free-vs-enterprise per author), so on most PRs it's legitimately skipped -- and a required check whose job is skipped sits at "Expected -- Waiting for status" forever, blocking merge (the same trap that stranded Dependabot PRs on the e2e-* checks). Add a dependency-review-gate job that always runs and collapses every smoke job into one pass/fail signal: it fails iff any job that ran ended in failure or was cancelled; success and skipped both pass. This is the single check intended to be marked required later -- it satisfies Dependabot/fork PRs (which run Firewall-free) and maintainer PRs (Firewall-enterprise) alike, and turns a Socket Firewall BLOCK into a merge-blocking failure instead of a non-required job nobody is forced to run. Scaffolding only: the gate is not yet added to branch protection's required checks (deferred until it's merged to main and observed reporting). Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore: bump CLI to 2.4.5 and require socketdev>=3.2.1 Follows the 2.4.4 release (SDK >=3.2.0) by picking up socketdev 3.2.1. Regenerates uv.lock to the published 3.2.1 release; no CLI logic changes. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --------- Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
chore(deps): bump socketdev floor to >=3.2.0 (CE-225) (#222) Pick up socketdev 3.2.0, which adds OTHER = "other" to SocketCategory so the backend's "other" alert category no longer triggers the "Unknown SocketCategory" warning fallback (SDK PR #85). No CLI logic changes. Bump CLI to 2.4.1 (on top of the 2.4.0 license-details fix). uv.lock regenerated against socketdev 3.2.0. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
feat(reach): add unified --exclude-paths, deprecate --reach-exclude-p… …aths (#227) Add a single --exclude-paths flag (Node CLI parity) that filters BOTH SCA manifest discovery and reachability analysis: - New Core matcher: anchored micromatch-style globs compiled to regex (no new deps). Scan-root-relative POSIX paths, '*' does not cross '/', '**' does, each pattern P expanded to [P, P/**]. Threaded into find_files via cli_config; no-op when unset. - Reach side unions --exclude-paths with the now-deprecated --reach-exclude-paths and forwards to coana --exclude-dirs. - Validation mirrors Node's assertValidExcludePaths (rejects negation, absolute paths, '..' traversal, degenerate match-everything; trailing slash stripped so '**/' is rejected). Accepts comma-strings and config-file lists. - --reach-exclude-paths soft-deprecated: still works, [DEPRECATED] in help, warns at runtime. Docs: document --exclude-paths under 'Path and File' (it affects every scan, not just reach), mark --reach-exclude-paths deprecated, and refresh the reachability flag table (--reach-analysis-timeout/-memory-limit primary names, --reach-debug, --reach-disable-external-tool-checks, defaults delegated to coana). Adds a CHANGELOG 2.4.3 entry and tests incl. the Node parity cases, validation, and config-file paths.
feat(reach): align reachability flags and coana env with Node CLI (#226) Bring the Python CLI's reachability surface to parity with the Node CLI: - --reach-disable-external-tool-checks -> coana --disable-external-tool-checks - forward SOCKET_CLI_VERSION + SOCKET_CALLER_USER_AGENT to coana (proxy is left to coana, which reads/inherits HTTPS_PROXY/HTTP_PROXY itself) - omit SOCKET_REPO_NAME/SOCKET_BRANCH_NAME for the default repo/branch sentinels - Node-style --reach-analysis-timeout/--reach-analysis-memory-limit as primary names, --reach-timeout/--reach-memory-limit kept as hidden aliases - --reach-debug -> coana --debug (global --enable-debug -> -d unchanged) - retry tier1 finalize with exponential backoff (3 attempts), never raising Memory-limit and concurrency are intentionally NOT hardcoded: coana already defaults to 8192 MB and concurrency 1, so the CLI omits the flags and lets coana apply them (and still forwards an explicit value when the user sets one). Splitting stays explicitly disabled (--disable-analysis-splitting) because coana defaults it ON. Removes stray always-on WARNING logging in the reachability runner. Adds a CHANGELOG 2.4.2 entry and tests for the flags/aliases, the coana command/env builder, and finalize retry.
Bundle pyenv in the Docker image for on-demand Python versions (#225) * Add pyenv to Docker image for on-demand Python versions Install pyenv (pinned to v2.7.1) just below uv, along with the Alpine build dependencies needed to compile CPython from source. This lets the bundled tooling build/install arbitrary Python versions on demand. Only the `pyenv` binary is symlinked onto the PATH; pyenv's shims directory is deliberately left off PATH so its shims don't shadow the system Python that the CLI runs on. bash is required since pyenv and the pyenv-installer are bash scripts. * Release 2.4.1: bundle pyenv in the Docker image Bump version to 2.4.1 and document the pyenv addition. The CLI is unchanged; this release exists to publish a Docker image that includes pyenv for on-demand Python version installation.
Always omit license details from full-scan diff request (#221) * fix(core): always omit license details from full-scan diff request (#CE-224 follow-on) The full-scan diff request (fullscans.stream_diff) now always sets include_license_details=false, decoupled from the --exclude-license-details flag. This prevents the CE-224 truncation crash (Unterminated string / JSON parse failure on large repos, reported by the tremendous org) from recurring even when the flag is not passed. Why this is safe (no output changes): the license fields the diff endpoint can embed are never consumed off the diff. With --generate-license off, the only consumer (the legal/FOSSA artifact builder) never runs. With --generate-license on, get_license_text_via_purl re-fetches license data from the dedicated PURL endpoint and overwrites whatever the diff embedded before anything reads it. Either way the embedded payload was dead weight that only bloated the response. --exclude-license-details still works but its scope is now narrower: it controls only the dashboard report URL, not the internal diff payload. Help text updated. Core.get_added_and_removed_packages(..., include_license_details=True) remains as an explicit override seam (exercised in tests). Minor bump to 2.4.0: outputs are provably unchanged, but this is a deliberate default-behavior change (2.3.0 made the flag propagate; 2.4.0 makes the lean diff the default), which warrants a minor bump per the project's semver policy. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore: trim changelog release notes * chore: require socketdev 3.1.2 * docs: note exclude license flag scope change --------- Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
feat(core): brotli-compress .socket.facts.json on full-scan upload (#219 ) Compress the reachability facts file to a `.socket.facts.json.br` multipart part before uploading it as part of a full scan. The Socket API transparently decompresses parts named exactly `.socket.facts.json.br` and stores plain JSON, so the stored result is unchanged while the on-the-wire payload shrinks by roughly 10-40x for typical facts files. This keeps large tier-1 reachability facts files under the API's per-file upload size cap. Previously an oversized facts file made the full-scan upload fail (surfaced as an HTTP 4xx/502 with the scan stuck and no report produced). - Compress at the upload boundary (Core.create_full_scan); the on-disk file is left untouched so local consumers still read plain .socket.facts.json. - Only files whose basename is exactly .socket.facts.json are compressed (the API matches that exact name); a custom --reach-output-file name and empty placeholder files are left as plain uploads. - Stream in 1 MiB chunks so large files aren't held fully in memory. - Never blocks an upload: any compression failure falls back to the plain file, and a partially-written .socket.facts.json.br is removed rather than left behind in the target directory. - Add brotli (CPython) / brotlicffi (PyPy) dependency.
Configurable CLI exit behavior for API errors (#211) * feat: add --exit-code-on-api-error flag + Buildkite-aware infra error logging Adds a configurable exit code for API/infrastructure failures so CI pipelines can distinguish them from blocking security findings (exit 1), without changing any default behavior. - New CliConfig field exit_code_on_api_error (default 3) + --exit-code-on-api-error flag. The CLI already exited 3 on unexpected errors; this just makes that code configurable (e.g. remap to a Buildkite soft_fail code, or 0 to swallow). - New _emit_infrastructure_error helper + IS_BUILDKITE gate: emits Buildkite log section markers (^^^ +++ / ---⚠️ ) and a soft_fail hint when running in Buildkite; plain log.error elsewhere so markers don't leak as literal text. - Wire the top-level generic-exception handler in cli() through the helper and the configurable code. Deliberately NON-breaking for 2.3.x: - --disable-blocking STILL forces exit 0 for all outcomes and takes precedence over --exit-code-on-api-error (documented in the flag help so the two aren't combined by mistake). - Default exit codes are unchanged; the exit code only changes when the user explicitly passes the flag. The breaking variant (infra errors bypassing --disable-blocking, distinct RequestTimeoutExceeded handling, exit 1 -> 3 for diff API failures) is intentionally deferred to a future 3.0 release. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * feat(config): auto-truncate commit messages over 200 chars The --commit-message flag passes its value directly into the API request URL as a query parameter with no length limit. AI-generated commit messages and the common CI pattern of concatenating $BUILDKITE_BUILD_NUMBER + $BUILDKITE_MESSAGE can easily exceed URL length limits, producing HTTP 413 errors. The 413 originates from an infrastructure-layer URL length limit (nginx/Cloudflare), not application-level validation -- confirmed via inspection of the Socket API route handler, which has no constraint on commit_message (unlike committers, which enforces <= 200 chars and returns a clean 400). 200 chars chosen as a conservative defensive ceiling given URL encoding can 2-3x raw character count. No customer should ever want a 2000-character commit message in their scan metadata. A backend-side validation (returning 400 instead of 413) is filed as a follow-on for the depscan API team. Motivated by customer incidents (Plaid). Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * pass timeout through SDK diff requests Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * fix: propagate --exclude-license-details to the full-scan diff request The full-scan diff comparison ignored --exclude-license-details: the flag was applied to full-scan params and report URLs but never forwarded to the fullscans.stream_diff request, so diff comparisons always fetched license details regardless of the flag. Thread it through get_added_and_removed_packages -> stream_diff via a new include_license_details param (defaulting True to preserve current behavior). Non-breaking: the APIFailure handling at this call site is deliberately left as-is (exit 1, --disable-blocking -> 0). Re-routing diff APIFailures through the top-level exit-3 path is part of the 3.0 exit-code change, not this one. Originally from the unreleased PR #195 branch; the timeout-propagation half already landed in the preceding commit. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * test: cover --exit-code-on-api-error, truncation, and Buildkite formatting tests/unit/test_cli_config.py - exit_code_on_api_error default 3 / custom / zero - commit-message truncation: passthrough under 200, truncate over 200, quote-strip-before-truncate tests/unit/test_socketcli.py - unexpected error exits 3 by default - --exit-code-on-api-error 100 remaps the failure exit code - --disable-blocking OVERRIDES --exit-code-on-api-error (-> 0): locks in the documented precedence so the soft_fail guidance can't silently regress - KeyboardInterrupt still exits 2 - _emit_infrastructure_error: BK markers + soft_fail hint only when IS_BUILDKITE; traceback gated on include_traceback Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore(release): 2.3.0 -- configurable API-error exit code Minor bump for the new --exit-code-on-api-error flag and the supporting non-breaking improvements (commit-message truncation, Buildkite-aware infra error logging, --timeout / --exclude-license-details fixes). This release is intentionally NON-breaking: default exit codes are unchanged, the exit code only shifts when --exit-code-on-api-error is explicitly passed, and --disable-blocking keeps its existing precedence. The breaking exit-code behavior change (infra errors exiting non-zero even under --disable-blocking) is deferred to a future 3.0. CHANGELOG + README document the flag AND its interaction with --disable-blocking (which overrides it) to reduce user error in the Buildkite soft_fail setup. Version refs synced across pyproject.toml, socketsecurity/__init__.py, and uv.lock (per the version-incrementation CI check). Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --------- Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
Bundle dependency updates, harden Dependabot reviews (#207) * chore: prettify, sort, and round out .gitignore Reorganizes .gitignore into labeled sections (Python cache, venvs, build artifacts, IDE, OS, logs, env files, generated output, project scratch, Conductor) with sorted entries within each group and trailing slashes on directory patterns for clarity. Folds in three smaller intents that would otherwise be separate commits: - Add .context/ for Conductor workspaces (collaboration scratch) - Add coverage.xml + .pytest_cache/ to fully cover pytest-cov outputs (.coverage.* and htmlcov/ were already on main from prior work) - Add *.swp / *.swo for vim swap files Drops the stale `*.cpython-312.pyc\`` line with a literal-backtick typo; it wasn't matching anything and `*.pyc` already covers the case. No behavior changes anyone would notice from the resulting rule set. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * ci: add .github/dependabot.yml to tame Dependabot PR noise The repo had no explicit Dependabot config, so Dependabot ran on full defaults: one PR per package per manifest, across every manifest in the tree -- including the e2e test fixtures that are intentionally crafted to exercise Socket's scanner. The cumulative result was the "PR pileup" this PR is consolidating. New config: - uv ecosystem (main app): grouped weekly into ONE minor/patch PR and one major PR; matches the existing python:uv labeling - github-actions: grouped weekly into ONE minor/patch PR - docker: separate weekly PR per Dockerfile change - 7-day cooldown across all ecosystems to give upstream time to pull bad releases - e2e fixtures (tests/e2e/fixtures/{simple-npm,simple-pypi}) are INTENTIONALLY excluded -- their pins should be chosen for supply- chain signal, not auto-bumped (this is why we had three fixture PRs in the cleanup) Pattern adapted from SocketDev/socket-basics. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * ci: add dependabot-review workflow with Socket Firewall smoke jobs For every Dependabot-authored PR, inspect what changed and conditionally run Socket Firewall (sfw) install smoke jobs against the affected manifests. Because sfw uses the anonymous Socket public-data API it needs NO secret, so this runs cleanly under the standard `pull_request` context -- no pull_request_target, no token-leak surface. Jobs (all conditional on file diff): - python-sfw-smoke: pyproject.toml / uv.lock -> `sfw uv sync` plus an import smoke on the modules that depend on the upgraded packages (cryptography, gitpython, requests, ...). Catches API-removal breaks from minor/patch deprecations. - fixture-npm-sfw-smoke: tests/e2e/fixtures/simple-npm/** -> `sfw npm install` in a clean cwd. - fixture-pypi-sfw-smoke: tests/e2e/fixtures/simple-pypi/** -> `sfw pip install -r requirements.txt` in a clean venv. - dockerfile-smoke: `docker build --pull` (no push) when the Dockerfile changes. - workflow-notice: Flag Dependabot PRs that touch workflow or dependabot config files for explicit human review (anti-supply-chain-confusion guardrail). Pattern adapted from SocketDev/socket-basics dependabot-review.yml. Action SHAs match the pins already in python-tests.yml and e2e-test.yml so zizmor stays happy. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * ci: add lock-drift, import-smoke, and pip-audit; skip e2e on dependabot python-tests.yml: - `uv lock --locked` -- fails if uv.lock has drifted from pyproject.toml. Prevents the "forgot to commit the lockfile" class of mistake. - Import smoke step that loads every top-level module touching the upgraded packages (cryptography, gitpython, requests, urllib3, ...). Catches API-removal breaks from minor/patch deprecations that the unit suite alone wouldn't surface. - `uvx pip-audit --strict` against the synced env -- light CVE check on the resolved transitive tree. Runs in seconds via uv's caching. e2e-test.yml: - Skip e2e on Dependabot PRs. They don't have access to the Socket API secret so e2e would always fail on them, polluting the PR check UI. Supply-chain risk for dep bumps is covered by dependabot-review.yml's Socket Firewall smoke jobs, which need no secrets. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * ci: fix pip-audit invocation to scan exported requirements `uvx pip-audit --disable-pip` requires `-r` plus either hashed requirements or `--no-deps`. The previous invocation crashed at start. Now: export the locked deps via `uv export --no-hashes --no-emit-project` into a tmp requirements file (skipping the local editable install of the project itself), then feed that to pip-audit with `--disable-pip --no-deps`. Verified locally -- no known vulnerabilities found across the 85 locked transitive deps. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore(deps): bump 9 main-app dependencies to latest Bundles the nine open Dependabot PRs against the main app into a single uv.lock regeneration. Where Dependabot's target trailed the latest published release, we went to the current latest and re-verified through sfw: - urllib3 2.6.3 -> 2.7.0 (closes #200) - gitpython 3.1.46 -> 3.1.50 (closes #198) - python-dotenv 1.2.1 -> 1.2.2 (closes #190) - pytest 9.0.2 -> 9.0.3 (closes #188) - uv 0.9.21 -> 0.11.17 (closes #210; Dependabot targeted 0.11.15) - cryptography 46.0.5 -> 46.0.7 (closes #181) - pygments 2.19.2 -> 2.20.0 (closes #177) - requests 2.32.5 -> 2.33.0 (closes #175) - idna 3.11 -> 3.15 (closes #205, CVE-2026-45409) idna 3.14 fixed CVE-2026-45409 -- a quadratic-time DoS via oversized inputs that bypassed the earlier CVE-2024-3651 mitigation. The rest are hygiene. All nine final versions verified clean through Socket Firewall (sfw) on the full transitive tree. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore(deps): bump e2e fixture manifests Closes the open Dependabot PRs against the e2e test fixtures. axios went to the current latest (1.16.1) rather than Dependabot's 1.16.0 target: - tests/e2e/fixtures/simple-npm: axios 1.15.0 -> 1.16.1 (closes #209) - tests/e2e/fixtures/simple-pypi: requests 2.31.0 -> 2.33.0 (closes #187) - tests/e2e/fixtures/simple-pypi: flask 3.0.0 -> 3.1.3 (closes #186) These fixtures were stale rather than intentionally pinned. Socket Firewall verified the install paths. The new .github/dependabot.yml intentionally excludes tests/e2e/fixtures/** from future auto-bumps. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> * chore(release): 2.2.93 with CHANGELOG backfill Patch release. Scope is maintenance only: dependency bundle + Dependabot review hardening + housekeeping + CHANGELOG backfill. No behavior changes. Targets 2.2.93 (not 2.2.92) to stay ahead of an in-flight 2.2.92 bug-fix release landing separately. CHANGELOG: 2.2.93 entry for this PR, plus backfilled entries for 2.2.81, 2.2.85, 2.2.86, 2.2.88, 2.2.89, and 2.2.91 (the #180 backfill covered 2.2.74-2.2.80; main reached 2.2.91 via #199 without a CHANGELOG note). Version refs synced across pyproject.toml, socketsecurity/__init__.py, and uv.lock per the version-incrementation CI check. Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --------- Signed-off-by: lelia <2418071+lelia@users.noreply.github.com>
PreviousNext