Agent skill

security-ownership-map

Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions.

Stars 164
Forks 32

Install this agent skill to your Project

npx add-skill https://github.com/tercumantanumut/selene/tree/main/lib/skills/catalog/bundled/security-ownership-map

SKILL.md

Security Ownership Map

Overview

Build a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.

Requirements

  • Python 3
  • networkx (required; community detection is enabled by default)

Install with:

bash
pip install networkx

Workflow

  1. Scope the repo and time window (optional --since/--until).
  2. Decide sensitivity rules (use defaults or provide a CSV config).
  3. Build the ownership map with ${SELENE_SKILL_ROOT}/scripts/run_ownership_map.py (co-change graph is on by default; use --cochange-max-files to ignore supernode commits).
  4. Communities are computed by default; graphml output is optional (--graphml).
  5. Query the outputs with ${SELENE_SKILL_ROOT}/scripts/query_ownership.py for bounded JSON slices.
  6. Persist and visualize (see ${SELENE_SKILL_ROOT}/references/neo4j-import.md).

By default, the co-change graph ignores common “glue” files (lockfiles, .github/*, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with --cochange-exclude or --no-default-cochange-excludes. Dependabot commits are excluded by default; override with --no-default-author-excludes or add patterns via --author-exclude-regex.

If you want to exclude Linux build glue like Kbuild from co-change clustering, pass:

bash
python "${SELENE_SKILL_ROOT}/scripts/run_ownership_map.py \
  --repo /path/to/linux \
  --out ownership-map-out \
  --cochange-exclude "**/Kbuild"

Quick start

Run from the repo root:

bash
python "${SELENE_SKILL_ROOT}/scripts/run_ownership_map.py \
  --repo . \
  --out ownership-map-out \
  --since "12 months ago" \
  --emit-commits

Defaults: author identity, author date, and merge commits excluded. Use --identity committer, --date-field committer, or --include-merges if needed.

Example (override co-change excludes):

bash
python "${SELENE_SKILL_ROOT}/scripts/run_ownership_map.py \
  --repo . \
  --out ownership-map-out \
  --cochange-exclude "**/Cargo.lock" \
  --cochange-exclude "**/.github/**" \
  --no-default-cochange-excludes

Communities are computed by default. To disable:

bash
python "${SELENE_SKILL_ROOT}/scripts/run_ownership_map.py \
  --repo . \
  --out ownership-map-out \
  --no-communities

Sensitivity rules

By default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:

# pattern,tag,weight
**/auth/**,auth,1.0
**/crypto/**,crypto,1.0
**/*.pem,secrets,1.0

Use it with --sensitive-config path/to/sensitive.csv.

Output artifacts

ownership-map-out/ contains:

  • people.csv (nodes: people)
  • files.csv (nodes: files)
  • edges.csv (edges: touches)
  • cochange_edges.csv (file-to-file co-change edges with Jaccard weight; omitted with --no-cochange)
  • summary.json (security ownership findings)
  • commits.jsonl (optional, if --emit-commits)
  • communities.json (computed by default from co-change edges when available; includes maintainers per community; disable with --no-communities)
  • cochange.graph.json (NetworkX node-link JSON with community_id + community_maintainers; falls back to ownership.graph.json if no co-change edges)
  • ownership.graphml / cochange.graphml (optional, if --graphml)

people.csv includes timezone detection based on author commit offsets: primary_tz_offset, primary_tz_minutes, and timezone_offsets.

LLM query helper

Use ${SELENE_SKILL_ROOT}/scripts/query_ownership.py to return small, JSON-bounded slices without loading the full graph into context.

Examples:

bash
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out community --id 3

Use --community-top-owners 5 (default) to control how many maintainers are stored per community.

Basic security queries

Run these to answer common security ownership questions with bounded output:

bash
# Orphaned sensitive code (stale + low bus factor)
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code

# Hidden owners for sensitive tags
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners

# Sensitive hotspots with low bus factor
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots

# Auth/crypto files with bus factor <= 1
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1

# Who is touching sensitive code the most
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10

# Co-change neighbors (cluster hints for ownership drift)
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20

# Community maintainers (for a cluster)
python "${SELENE_SKILL_ROOT}/scripts/query_ownership.py --data-dir ownership-map-out community --id 3

# Monthly maintainers for the community containing a file
python "${SELENE_SKILL_ROOT}/scripts/community_maintainers.py \
  --data-dir ownership-map-out \
  --file network/card.c \
  --since 2025-01-01 \
  --top 5

# Quarterly buckets instead of monthly
python "${SELENE_SKILL_ROOT}/scripts/community_maintainers.py \
  --data-dir ownership-map-out \
  --file network/card.c \
  --since 2025-01-01 \
  --bucket quarter \
  --top 5

Notes:

  • Touches default to one authored commit (not per-file). Use --touch-mode file to count per-file touches.
  • Use --window-days 90 or --weight recency --half-life-days 180 to smooth churn.
  • Filter bots with --ignore-author-regex '(bot|dependabot)'.
  • Use --min-share 0.1 to show stable maintainers only.
  • Use --bucket quarter for calendar quarter groupings.
  • Use --identity committer or --date-field committer to switch from author attribution.
  • Use --include-merges to include merge commits (excluded by default).

Summary format (default)

Use this structure, add fields if needed:

json
{
  "orphaned_sensitive_code": [
    {
      "path": "crypto/tls/handshake.rs",
      "last_security_touch": "2023-03-12T18:10:04+00:00",
      "bus_factor": 1
    }
  ],
  "hidden_owners": [
    {
      "person": "alice@corp",
      "controls": "63% of auth code"
    }
  ]
}

Graph persistence

Use ${SELENE_SKILL_ROOT}/references/neo4j-import.md when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.

Notes

  • bus_factor_hotspots in summary.json lists sensitive files with low bus factor; orphaned_sensitive_code is the stale subset.
  • If git log is too large, narrow with --since or --until.
  • Compare summary.json against CODEOWNERS to highlight ownership drift.

Expand your agent's capabilities with these related and highly-rated skills.

tercumantanumut/selene

app-mockup

Create deterministic browser, tablet, laptop, and phone mockups from real screenshots via the local TypeScript renderer in this plugin. Use for marketing visuals, store screenshots, and framed UI previews without ML image generation.

164 32
Explore
tercumantanumut/selene

chatgpt-apps

Build, scaffold, refactor, and troubleshoot ChatGPT Apps SDK applications that combine an MCP server and widget UI. Use when Codex needs to design tools, register UI resources, wire the MCP Apps bridge or ChatGPT compatibility APIs, apply Apps SDK metadata or CSP or domain settings, or produce a docs-aligned project scaffold. Prefer a docs-first workflow by invoking the openai-docs skill or OpenAI developer docs MCP tools before generating code.

164 32
Explore
tercumantanumut/selene

screenshot

Use when the user explicitly asks for a desktop or system screenshot (full screen, specific app or window, or a pixel region), or when tool-specific capture capabilities are unavailable and an OS-level capture is needed.

164 32
Explore
tercumantanumut/selene

gh-fix-ci

Use when a user asks to debug or fix failing GitHub PR checks that run in GitHub Actions; use `gh` to inspect checks and logs, summarize failure context, draft a fix plan, and implement only after explicit approval. Treat external providers (for example Buildkite) as out of scope and report only the details URL.

164 32
Explore
tercumantanumut/selene

speech

Use when the user asks for text-to-speech narration or voiceover, accessibility reads, audio prompts, or batch speech generation via the OpenAI Audio API; run the bundled CLI (`${SELENE_SKILL_ROOT}/scripts/text_to_speech.py`) with built-in voices and require `OPENAI_API_KEY` for live calls. Custom voice creation is out of scope.

164 32
Explore
tercumantanumut/selene

doc

Use when the task involves reading, creating, or editing `.docx` documents, especially when formatting or layout fidelity matters; prefer `python-docx` plus the bundled `${SELENE_SKILL_ROOT}/scripts/render_docx.py` for visual checks.

164 32
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results