diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4867981 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,32 @@ +# Rust artifacts +target/ +**/*.rs.bk + +# Python artifacts +__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ +.coverage +htmlcov/ + +# Environments +.venv/ +venv/ +env/ +.env + +# Git and IDEs +.git +.gitignore +.idea/ +.vscode/ + +# Docker +Dockerfile +.dockerignore + +# Packaging +dist/ +build/ +*.egg-info/ diff --git a/.gitignore b/.gitignore index 0cf8023..4ed39ab 100644 --- a/.gitignore +++ b/.gitignore @@ -60,5 +60,12 @@ venv.bak/ # IDEs .idea/ +.vscode/ + +# Claude Code memory +.claude/ + +# Rust build artifacts +target/ .vscode/target/ Cargo.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..3e955d3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,60 @@ +default_stages: [pre-commit] +minimum_pre_commit_version: "3.6.0" + +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-yaml + + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.11.10 + hooks: + - id: ruff + name: ruff (lint + fix) + args: [--fix] + types: [python] + pass_filenames: true + - id: ruff-format + name: ruff (format) + types: [python] + pass_filenames: true + + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.15.0 + hooks: + - id: mypy + args: [--config-file=pyproject.toml] + files: ^src/.*\.py$ + pass_filenames: true + + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + args: [--baseline, .secrets.baseline] + exclude: ^tests/examples/hardcoded_anthropic_key\.py$ + pass_filenames: true + + - repo: https://github.com/commitizen-tools/commitizen + rev: v3.31.0 + hooks: + - id: commitizen + stages: [commit-msg] + + - repo: local + hooks: + - id: cargo-fmt + name: cargo fmt --check + entry: cargo fmt --all -- --check + language: system + types: [rust] + pass_filenames: false + - id: cargo-clippy + name: cargo clippy -- -D warnings + entry: cargo clippy --all-targets --all-features -- -D warnings + language: system + types: [rust] + pass_filenames: false diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..1fe4c09 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,11 @@ +repos: + - repo: local + hooks: + - id: pyspector + name: PySpector SAST + entry: pyspector + args: ["scan", "."] + language: system + types: [python] + pass_filenames: false + always_run: true diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..b4a3502 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,162 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], + "results": { + "pluginconfig\\aipocgen.json": [ + { + "type": "Secret Keyword", + "filename": "pluginconfig\\aipocgen.json", + "hashed_secret": "ebdd1ec9aa35020a4ad2462cc13fb4ff7cfcdabe", + "is_verified": false, + "line_number": 3 + } + ], + "plugins\\aipocgen.py": [ + { + "type": "Secret Keyword", + "filename": "plugins\\aipocgen.py", + "hashed_secret": "49697e763a0dda5673303db0e2a91c309ed73c2d", + "is_verified": false, + "line_number": 14 + } + ], + "tests\\examples\\hardcoded_anthropic_key.py": [ + { + "type": "Base64 High Entropy String", + "filename": "tests\\examples\\hardcoded_anthropic_key.py", + "hashed_secret": "7f19eed39c278717993314fc0a25b3e6cad41416", + "is_verified": false, + "line_number": 1 + }, + { + "type": "Secret Keyword", + "filename": "tests\\examples\\hardcoded_anthropic_key.py", + "hashed_secret": "7f19eed39c278717993314fc0a25b3e6cad41416", + "is_verified": false, + "line_number": 1 + } + ] + }, + "generated_at": "2026-05-11T08:38:25Z" +} diff --git a/pyproject.toml b/pyproject.toml index 1e62e38..fc94a2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,3 +4,31 @@ requires = [ "setuptools-rust>=1.0" ] build-backend = "setuptools.build_meta" + +[tool.ruff] +line-length = 100 +target-version = "py310" +extend-exclude = [ + "frontend/node_modules", + "src/pyspector.egg-info", +] + +[tool.ruff.lint] +select = ["E", "F", "I"] +ignore = ["E501"] + +[tool.mypy] +python_version = "3.10" +files = ["src"] +ignore_missing_imports = true +show_error_codes = true +pretty = true +disable_error_code = [ + "arg-type", + "assignment", + "attr-defined", + "import-untyped", + "misc", + "var-annotated", +] +exclude = "(^frontend/node_modules/|^src/pyspector\\.egg-info/)"