Spaces:
Sleeping
Sleeping
| # Policy checks: root semgrep.yml is copied from the parser repo (sync with | |
| # install -m0644 "$(PARSER_ROOT)/semgrep.yml" "$(CURDIR)/semgrep.yml" | |
| # or refresh when parser policy changes). Cursor hooks/rules: scripts/install_cursor_from_parser.sh | |
| PARSER_ROOT ?= $(HOME)/PycharmProjects/parser | |
| PYTHON ?= $(shell if test -x "$(CURDIR)/.venv/bin/python"; then echo "$(CURDIR)/.venv/bin/python"; else command -v python3; fi) | |
| SEMGREP_BIN ?= $(CURDIR)/.venv/bin/semgrep | |
| SEMGREP_CONFIG ?= $(CURDIR)/semgrep.yml | |
| MUTMUT_STATS ?= $(CURDIR)/mutants/mutmut-cicd-stats.json | |
| MUTMUT_MIN_SCORE ?= 100 | |
| MUTMUT_MAX_SURVIVED ?= 0 | |
| MUTMUT_MAX_TIMEOUT ?= 0 | |
| MUTMUT_MAX_NO_TESTS ?= 0 | |
| # Broad-scan excludes: parser-parity rules that are not yet adopted repo-wide (trim over time). | |
| SEMGREP_KINK_EXCLUDE_RULES ?= \ | |
| python-enforce-readable-line-length \ | |
| python-no-single-leading-underscore-identifiers \ | |
| python-no-any-annotation \ | |
| python-no-default-parameters \ | |
| python-no-bare-collection-annotations \ | |
| python-no-keyword-only-separator \ | |
| python-no-os-environ \ | |
| python-no-nested-functions \ | |
| python-no-try-except-anywhere \ | |
| python-no-importlib-import-module \ | |
| python-no-import-aliases \ | |
| python-no-defensive-dict-list-isinstance \ | |
| python-no-basemodel-outside-models-py \ | |
| python-no-dataclasses \ | |
| python-no-defensive-get-with-or-default \ | |
| python-no-getattr-non-dunder | |
| SEMGREP_EXCLUDE_FLAGS := $(foreach r,$(SEMGREP_KINK_EXCLUDE_RULES),--exclude-rule $(r)) | |
| .PHONY: semgrep-kink semgrep-recsys-core semgrep-recsys-strict ruff-kink dead-kink policy-kink test mutation-python recsys-benchmark adv-probes-http prove-hf-media-placeholder publish-hf-verify verify-hf-live | |
| # Python sources only (exclude data/, audit/node_modules, deploy artifacts). | |
| semgrep-kink: | |
| "$(SEMGREP_BIN)" --config "$(SEMGREP_CONFIG)" $(SEMGREP_EXCLUDE_FLAGS) \ | |
| "$(CURDIR)/backend" \ | |
| "$(CURDIR)/scripts" \ | |
| "$(CURDIR)/tests" \ | |
| "$(CURDIR)/api.py" \ | |
| "$(CURDIR)/app.py" \ | |
| "$(CURDIR)/models.py" \ | |
| "$(CURDIR)/ingest.py" \ | |
| "$(CURDIR)/fetlife_collect.py" \ | |
| "$(CURDIR)/fetlife_auth.py" \ | |
| "$(CURDIR)/cdp_fetlife.py" \ | |
| "$(CURDIR)/import_fetlife_sample.py" \ | |
| "$(CURDIR)/import_fetlife_kinktionary.py" \ | |
| "$(CURDIR)/inspect_fetlife.py" \ | |
| "$(CURDIR)/download_kinktionary.py" | |
| # Recommender-related modules (expect findings until debt is fixed; use for local triage). | |
| semgrep-recsys-core: | |
| "$(SEMGREP_BIN)" --config "$(SEMGREP_CONFIG)" $(SEMGREP_EXCLUDE_FLAGS) \ | |
| "$(CURDIR)/backend/models.py" \ | |
| "$(CURDIR)/backend/recsys_data.py" \ | |
| "$(CURDIR)/backend/recsys_ots.py" \ | |
| "$(CURDIR)/backend/recsys_metrics.py" \ | |
| "$(CURDIR)/backend/recsys_benchmark.py" \ | |
| "$(CURDIR)/backend/recsys_graph.py" \ | |
| "$(CURDIR)/backend/recsys_mmr.py" \ | |
| "$(CURDIR)/backend/recommendations.py" \ | |
| "$(CURDIR)/backend/recsys_env_overrides.py" | |
| # Phase 0-A strict gate: typed recsys settings in models.py (no broad excludes). | |
| semgrep-recsys-strict: | |
| "$(SEMGREP_BIN)" --config "$(SEMGREP_CONFIG)" "$(CURDIR)/backend/models.py" | |
| # Phase 0-A: strict paths only (full-tree Ruff is still very noisy). | |
| RUFF_STAGED := $(CURDIR)/backend/models.py $(CURDIR)/scripts/recsys_benchmark.py $(CURDIR)/tests/test_recsys_ots.py | |
| ruff-kink: | |
| "$(PYTHON)" -m ruff check $(RUFF_STAGED) | |
| # Requires a git checkout (`dead` uses `git ls-files`). Uses `.dead-allowlist` at repo root. | |
| dead-kink: | |
| test -d "$(CURDIR)/.git" | |
| cd "$(CURDIR)" && "$(PYTHON)" -m dead --exclude '^(\.venv|audit|data|frontend|deploy|node_modules)/' --symbol-allowlist "$(CURDIR)/.dead-allowlist" | |
| policy-kink: ruff-kink semgrep-recsys-strict | |
| test: | |
| "$(PYTHON)" -m pytest -q | |
| mutation-python: | |
| "$(PYTHON)" -m mutmut run | |
| "$(PYTHON)" -m mutmut export-cicd-stats | |
| "$(PYTHON)" "$(CURDIR)/scripts/check_mutmut_stats.py" "$(MUTMUT_STATS)" \ | |
| --min-score "$(MUTMUT_MIN_SCORE)" \ | |
| --max-survived "$(MUTMUT_MAX_SURVIVED)" \ | |
| --max-timeout "$(MUTMUT_MAX_TIMEOUT)" \ | |
| --max-no-tests "$(MUTMUT_MAX_NO_TESTS)" | |
| # Build HF Docker image and assert missing ``/media/fetlife_fetishes/...`` returns JPEG fallback | |
| # (``KINK_HF_SPACE_IMAGE`` + strict env ignored). Requires Docker. | |
| prove-hf-media-placeholder: | |
| docker build -t kink-cli-prove-media:local "$(CURDIR)" | |
| "$(PYTHON)" "$(CURDIR)/scripts/prove_hf_media_placeholder.py" kink-cli-prove-media:local | |
| # Push this repo to the Docker Space, wait for RUNNING, then run scripts/verify_hf_stack.py on the app URL. | |
| # Needs HF_TOKEN (or HUGGING_FACE_HUB_TOKEN / hf auth / parser secrets.toml) and HF_SPACE_REPO or secrets [huggingface]. | |
| publish-hf-verify: | |
| "$(PYTHON)" "$(CURDIR)/scripts/publish_hf_space.py" --verify | |
| # Live Space smoke only (no upload). Example: make verify-hf-live HF_VERIFY_BASE_URL=https://owner-slug.hf.space | |
| verify-hf-live: | |
| @test -n "$(HF_VERIFY_BASE_URL)" || (echo >&2 "Set HF_VERIFY_BASE_URL=https://<owner>-<slug>.hf.space"; exit 2) | |
| HF_VERIFY_BASE_URL="$(HF_VERIFY_BASE_URL)" "$(PYTHON)" "$(CURDIR)/scripts/verify_hf_stack.py" --smoke --base-url "$(HF_VERIFY_BASE_URL)" | |
| # Partner/group HTTP probes (same as CI test_adversarial_partner_probes_script). | |
| adv-probes-http: | |
| KINK_PROBE_HTTP=1 KINK_SKIP_HEAVY_WARM=1 "$(PYTHON)" scripts/adversarial_partner_probes.py | |
| # Train Cornac + write candidates/benchmark (override --db / --user as needed). | |
| recsys-benchmark: | |
| "$(PYTHON)" scripts/recsys_benchmark.py --db data/store_slim.db | |