Files
watermarks-remover/Makefile
Guillaume Meyer (The Opinionated Man)andGitHub 09e64c4ded feat: optional MarkLLM text-watermark verification harness (#53)
* feat: optional MarkLLM text-watermark verification harness

Add an optional external backend wrapping THU-BPM/MarkLLM (Apache-2.0)
so a specific statistical text-watermark scheme (KGW / SynthID-Text)
can be verified before/after a Layer B rewrite.

- detect_text_watermark.py: detect/watermark subcommands, external
  checkout at a pinned commit, exit codes 0/1/2/3, --json
- rewrite_text.py --markllm-scheme: before/after detection around the
  rewrite, reports a `cleared` flag; never fails the rewrite when the
  backend is unavailable
- setup_markllm.sh + requirements-markllm.txt (pinned deps) +
  Dockerfile.markllm + Makefile bootstrap/smoke/docker targets
- tests/test_markllm_detect.py: 16 mock-based cases (no torch in CI)
- Docs: verification-harness caveat (same-config-only, not a
  vendor-detector oracle) in README, SKILL.md, removal-matrix, vendor-notes

* chore: tidy merged Unreleased changelog list

* security: harden the MarkLLM harness (offline, caps, supply-chain)

Addresses the PR security review:

- detect_text_watermark.py: --offline loads the scoring model from the HF
  cache only (local_files_only + HF_HUB_OFFLINE, no remote code), and the
  algorithm config is capped at 1 MiB so a crafted huge file is refused
  before either this script or upstream reads it into memory
- rewrite_text.py: WATERMARKS_MARKLLM_RLIMIT_AS (env, POSIX) optionally
  applies RLIMIT_AS to the MarkLLM subprocess; off by default because
  torch/CUDA needs large address spaces
- Dockerfile.markllm: drop the unpinned torch install (it is pinned in
  requirements-markllm.txt) and verify the cloned upstream commit SHA
- tests: offline flag, config-too-large, and preexec/rlimit cases
- docs: hardening knobs in README + SKILL.md; changelog updated
2026-08-14 09:56:16 -07:00

77 lines
2.8 KiB
Makefile

.PHONY: test smoke smoke-synthid bootstrap-synthid docker-synthid-build docker-synthid-help \
smoke-ctrlregen bootstrap-ctrlregen docker-ctrlregen-build docker-ctrlregen-help \
smoke-markllm bootstrap-markllm docker-markllm-build docker-markllm-help install-skill clean
SCRIPTS := skills/remove-ai-marks/scripts
PYTHON ?= $(shell if [ -x .venv/bin/python ]; then echo .venv/bin/python; else echo python3; fi)
test:
$(PYTHON) -m pytest
smoke:
-python3 $(SCRIPTS)/inspect_text.py tests/fixtures/sample_watermarked.txt
python3 $(SCRIPTS)/clean_text.py tests/fixtures/sample_watermarked.txt -o /tmp/wm.cleaned.txt --stats
python3 $(SCRIPTS)/rewrite_text.py tests/fixtures/sample_watermarked.txt --backend print-prompt >/dev/null
-python3 $(SCRIPTS)/inspect_file.py tests/fixtures/sample_ai.md
python3 $(SCRIPTS)/clean_file.py tests/fixtures/sample_ai.md -o /tmp/sample_ai.cleaned.md
python3 $(SCRIPTS)/clean_file.py tests/fixtures/sample_ai.html -o /tmp/sample_ai.cleaned.html
python3 $(SCRIPTS)/clean_file.py tests/fixtures/sample_meta.svg -o /tmp/sample_meta.cleaned.svg
@echo "smoke ok"
smoke-synthid:
@if [ -z "$(REVERSE_SYNTHID_DIR)" ]; then \
echo "smoke-synthid skipped (set REVERSE_SYNTHID_DIR)"; \
else \
$(PYTHON) $(SCRIPTS)/score_synthid.py --help >/dev/null && echo "score_synthid adapter present"; \
fi
bootstrap-synthid:
./skills/remove-ai-marks/scripts/setup_synthid.sh
docker-synthid-build:
docker build -f Dockerfile.synthid -t watermarks-remover-synthid-scorer .
docker-synthid-help:
docker run --rm watermarks-remover-synthid-scorer --help
smoke-ctrlregen:
@if [ -z "$(NOAI_WATERMARK_DIR)" ]; then \
echo "smoke-ctrlregen skipped (set NOAI_WATERMARK_DIR)"; \
else \
$(PYTHON) $(SCRIPTS)/clean_ctrlregen.py --help >/dev/null && echo "clean_ctrlregen adapter present"; \
fi
bootstrap-ctrlregen:
./skills/remove-ai-marks/scripts/setup_ctrlregen.sh
docker-ctrlregen-build:
docker build -f Dockerfile.ctrlregen -t watermarks-remover-ctrlregen .
docker-ctrlregen-help:
docker run --rm watermarks-remover-ctrlregen --help
smoke-markllm:
@if [ -z "$(MARKLLM_DIR)" ]; then \
echo "smoke-markllm skipped (set MARKLLM_DIR)"; \
else \
$(PYTHON) $(SCRIPTS)/detect_text_watermark.py --help >/dev/null && echo "detect_text_watermark adapter present"; \
fi
bootstrap-markllm:
./skills/remove-ai-marks/scripts/setup_markllm.sh
docker-markllm-build:
docker build -f Dockerfile.markllm -t watermarks-remover-markllm .
docker-markllm-help:
docker run --rm watermarks-remover-markllm --help
install-skill:
mkdir -p $(HOME)/.grok/skills
ln -sfn $(CURDIR)/skills/remove-ai-marks $(HOME)/.grok/skills/remove-ai-marks
@echo "linked -> $(HOME)/.grok/skills/remove-ai-marks"
clean:
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
rm -rf .pytest_cache .venv