Forensic authorship verification for GitLab CI/CD pipelines.
Detects commit author impersonation using deterministic stylometric analysis — pure rational arithmetic, bit-for-bit reproducible results.
Live demo: https://stylometry-ci-api-48658495111.us-central1.run.app/
Traditional security scanners inspect code for vulnerabilities. STYLOMETRY-CI inspects who wrote it.
When a commit arrives in a Merge Request, the gate analyzes the diff, message, timestamp, and churn metrics against the claimed author's historical behavioral baseline. If the behavioral DNA doesn't match, the pipeline fails.
Attack vectors detected:
- Account takeover (ATO) via stolen credentials
- Credential recycling and shared accounts
- Insider threats and privilege escalation via social engineering commits
- Base64 payload injection and obfuscated supply chain attacks
Stolen credentials. Social engineering message. Base64 payload injection. Three cores fire simultaneously and SYN-001 synergy applies. Pipeline fails with exit 1.
The agent receives the forensic report and reasons through the attack chain, then acts on the Merge Request via the GitLab MCP server.
Seven forensic cores run independently. Each contributes a rational penalty to the Multi-Criteria Profile (MCP). When two or more cores flag the same commit, a synergy multiplier scales the risk.
Raw commit (diff + message + metadata)
│
├── Behavioral Core — hour deviation, file volume, line churn
├── Entropy Core — Shannon/Gini entropy, base64 blob detection
├── Semiotic Core — social engineering patterns (EN + ES Rioplatense)
├── NLP / Register Core — TTR, lexical density, register drift
├── Chronobiology Core — circadian grid (56 weekly blocks)
├── Atomicity Core — git topology, directory dispersion ratio
└── Syntax Core — AST footprint, comprehension/lambda preference
│
MCP aggregation × synergy multiplier
│
PASS · WARN · REQUIRE_REVIEW · BLOCK
Key design principle: all metrics are stored and computed as fractions.Fraction — no IEEE 754 floating-point drift, no hardware-dependent rounding. Results are SHA-256 deterministic across any environment.
MCP thresholds:
| Verdict | Score | Pipeline action |
|---|---|---|
PASS |
< 0.20 | Merge allowed |
WARN |
0.20–0.35 | Logged, no block |
REQUIRE_REVIEW |
0.35–0.75 | Forensic report posted to MR, exit 0 |
BLOCK |
≥ 0.75 | Pipeline fails, exit 1, MR blocked |
stylometry-ci/
├── src/
│ ├── agent_tools_api.py # FastAPI app — forensic REST endpoints
│ ├── pipeline_gate.py # CLI gate runner
│ ├── policy_engine.py # MCP verdict engine (rational arithmetic)
│ ├── hydrate_profiles.py # Build author baseline from git history
│ ├── static/index.html # Landing page (served from GET /)
│ └── stylometry_core/
│ ├── behavioral_core.py
│ ├── entropy_core.py
│ ├── semiotic_core.py
│ ├── nlp_metrics.py
│ ├── register_drift_core.py
│ ├── commit_atomicity_core.py
│ └── syntax_fingerprint_core.py
├── adk_agent/
│ └── agent.py # Gemini ADK agent (GitLab MCP integration)
├── data/
│ └── dev_profiles.db # SQLite — author baseline profiles
├── tests/
├── Dockerfile
└── main.py # ADK agent entry point
git clone https://github.com/annatchijova/stylometry.git
cd stylometry
bash install.shinstall.sh creates a .venv, installs all dependencies, and prints the next steps.
pip install -r requirements.txtPython 3.12+. The forensic cores use only the standard library (fractions, sqlite3, subprocess, ast).
uvicorn src.agent_tools_api:app --reload --port 8080pytest tests/ -vAll 11 tests must pass. The determinism test (test_determinism.py) verifies SHA-256 reproducibility across 3 consecutive runs.
The gate needs a baseline before it can detect deviations. The hydration script reads real commit history from any local git repository and computes the rational metrics.
Step 1 — Clone the repository you want to use as baseline:
git clone https://github.com/YOUR_USER/YOUR_REPO.git ~/your-repoStep 2 — Check the exact author email used in that repo's commits:
git -C ~/your-repo log --format="%ae" | sort | uniq -c | sort -rn | head -5Step 3 — Run the hydration script:
cd ~/stylometry-ci
python3 src/hydrate_profiles.py \
--repo ~/your-repo \
--author "your.email@example.com" \
--db data/dev_profiles.dbStep 4 — Test the gate against your own commits:
python3 src/pipeline_gate.py \
--author "your.email@example.com" \
--diff path/to/diff.txt \
--message path/to/msg.txt \
--hour 14 --files 2 --lines 45 \
--commit-id "abc123" \
--db data/dev_profiles.dbAdd this job to your project's .gitlab-ci.yml:
stages:
- security
stylometry_gate:
stage: security
image: python:3.12-slim
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
before_script:
- apt-get update -qq && apt-get install -y -qq git
- pip install -r requirements.txt -q
script:
- echo "$CI_COMMIT_MESSAGE" > commit_msg.txt
- git diff $CI_MERGE_REQUEST_DIFF_BASE_SHA HEAD > commit_diff.txt
- HOUR=$(echo "$CI_COMMIT_TIMESTAMP" | cut -dT -f2 | cut -d: -f1)
- FILES=$(git diff $CI_MERGE_REQUEST_DIFF_BASE_SHA HEAD --name-only | wc -l)
- LINES=$(wc -l < commit_diff.txt)
- >
python3 src/pipeline_gate.py
--author "$CI_COMMIT_AUTHOR_EMAIL"
--diff commit_diff.txt
--message commit_msg.txt
--hour "${HOUR:-12}"
--files $FILES
--lines $LINES
--commit-id "$CI_COMMIT_SHA"
--timestamp "$CI_COMMIT_TIMESTAMP"
--db data/dev_profiles.db
--branch "$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"
artifacts:
reports:
sast: gate_result.sarif
paths:
- gate_result.json
expire_in: 30 days
when: alwaysNote: $CI_MERGE_REQUEST_DIFF_BASE_SHA is more reliable than HEAD~1 on shallow-clone runners.
The adk_agent/ module wraps the forensic API as a Gemini ADK agent. It connects to the GitLab MCP server to close compromised Merge Requests and post forensic reports directly to the MR thread.
Run locally:
uvicorn main:app --reload --port 8080Deploy to Cloud Run:
gcloud run deploy stylometry-ci-agent \
--source . \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars GOOGLE_CLOUD_PROJECT=YOUR_PROJECT,GOOGLE_GENAI_USE_VERTEXAI=1| Service | URL | Description |
|---|---|---|
| Forensic API | stylometry-ci-api-48658495111.us-central1.run.app | REST endpoints + landing page |
| ADK Agent | stylometry-ci-agent-48658495111.us-central1.run.app | Gemini agent + GitLab MCP |
by Olga Vasilieva · listen on Suno
Traditional scanners look for holes in the code,
They watch the configuration and the payload load.
But there's a massive blind spot in the modern pipeline:
Who actually committed this line by line?
Stolen credentials, credential recycling too,
An identity ghost trying to push something through.
They bypassed the token, they thought they were free,
But they just hit the wall of STYLOMETRY!
Chorus
STYLOMETRY-CI! The Forensic Identity Gate!
Failing the pipeline, sealing the impostor's fate!
Seven forensic cores running deep in the dark,
Leaving a deterministic, bit-for-bit mark!
No floating-point drift, no hardware-bound line,
Pure rational arithmetic guarding the design!
They forged the Git author, they matched the name,
But their behavioral DNA isn't the same.
We measure the entropy, the AST track,
The register drift when the syntax goes slack.
Circadian grids mapping hour and day,
Semiotic patterns in EN and Rioplatense play!
The Multi-Criteria Profile starts to ignite,
The synergy multiplier brings the fraud to the light!
Chorus
STYLOMETRY-CI! The Forensic Identity Gate!
Failing the pipeline, sealing the impostor's fate!
Seven forensic cores running deep in the dark,
Leaving a deterministic, bit-for-bit mark!
No floating-point drift, no hardware-bound line,
Pure rational arithmetic guarding the design!
If the verdict hits BLOCK, the MR is dead,
The Gemini agent posts the traces instead.
Connected to GitLab through MCP power,
Closing compromised requests in the very same hour!
Securing the supply chain, true evidence state,
You cannot fake your style at the Forensic Gate!
Account takeover? Blocked.
Obfuscated payloads? Blocked.
PASS · WARN · REVIEW · or shut down the gate.
SHA-256 secure. STYLOMETRY-CI.
Your code is your signature.
Anna Tchijova · Olga Vasilieva — 2026
Built for the Google Cloud Rapid Agent Hackathon · GitLab track
Licensed under Apache 2.0




