Skip to content

Latest commit

 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

STYLOMETRY-CI · Forensic Identity Gate

License: Apache 2.0 Python 3.12 Arithmetic: fractions.Fraction Hackathon: Google × GitLab 2026

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/


What it does

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

Demo

Scenario 3 — Malicious commit · BLOCK · MCP = 1.0

Stolen credentials. Social engineering message. Base64 payload injection. Three cores fire simultaneously and SYN-001 synergy applies. Pipeline fails with exit 1.

GitLab pipeline — FAILED

gate_result.json — BLOCK MCP=1.0 with full signal breakdown


Gemini ADK Agent · Forensic reasoning over GitLab MCP

The agent receives the forensic report and reasons through the attack chain, then acts on the Merge Request via the GitLab MCP server.

ADK agent — forensic analysis of supply chain attack

ADK agent — REQUIRE_REVIEW edge case reasoning (false positive detection)

ADK agent — insider threat + authority dropping scenario


Architecture

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

Project structure

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

Installation

git clone https://github.com/annatchijova/stylometry.git
cd stylometry
bash install.sh

install.sh creates a .venv, installs all dependencies, and prints the next steps.


Setup

Requirements

pip install -r requirements.txt

Python 3.12+. The forensic cores use only the standard library (fractions, sqlite3, subprocess, ast).

Run locally

uvicorn src.agent_tools_api:app --reload --port 8080

Run tests

pytest tests/ -v

All 11 tests must pass. The determinism test (test_determinism.py) verifies SHA-256 reproducibility across 3 consecutive runs.


Hydrating an author profile

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-repo

Step 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 -5

Step 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.db

Step 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.db

GitLab CI/CD integration

Add 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: always

Note: $CI_MERGE_REQUEST_DIFF_BASE_SHA is more reliable than HEAD~1 on shallow-clone runners.


Gemini ADK agent

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 8080

Deploy 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

Deployed services

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

The STYLOMETRY-CI Hymn

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.


Authors

Anna Tchijova · Olga Vasilieva — 2026
Built for the Google Cloud Rapid Agent Hackathon · GitLab track
Licensed under Apache 2.0

About

Forensic authorship gate for GitLab CI

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages