audit-flow
Interactive system flow tracing across CODE, API, AUTH, DATA, NETWORK layers with SQLite persistence and Mermaid export. Use for security audits, co…
它会碰到什么
逐条看命中(7 条严重或高危)
- 高
scripts/audit.py:32exec-spawncommit = subprocess.run(
- 高
scripts/audit.py:40exec-spawnbranch = subprocess.run(
- 高
scripts/audit.py:48exec-spawnstatus = subprocess.run(
- 高
scripts/audit.py:1565exec-spawnrepo_root = subprocess.run(
- 高
scripts/audit.py:1583exec-spawnsubprocess.run([
- 高
scripts/audit.py:1587exec-spawnsubprocess.run([
- 高
scripts/audit.py:1593exec-spawnsubprocess.run([
这一栏是扫描器报的事实,不是结论。命中多不等于有毒(安全工具、规则库、示例脚本本来就会包含危险写法),命中少也不等于干净。它和你手上的凭据、文件、网络有什么关系,需要你自己看。
技能内容
⚠️ MANDATORY ENTRY POINT — Execute Before ANY Other Action
Step 1: Read schema.sql
# ALWAYS read the schema first to understand tables, constraints, views
cat .claude/skills/audit-flow/schema.sql
Step 2: Check if DB exists — NEVER recreate
# Check for existing database
ls -la .audit/audit.db 2>/dev/null && echo "DB EXISTS - DO NOT RECREATE" || echo "No DB - safe to init"
Step 3: If DB exists, show current state
python .claude/skills/audit-flow/scripts/audit.py list
🚫 FORBIDDEN ACTIONS
| Action | Why Forbidden |
| ----------------------------------------------------- | ------------------------ |
| rm .audit/audit.db | Destroys audit history |
| audit.py init when DB exists | Overwrites existing data |
| DROP TABLE | Destroys audit history |
| sqlite3 .audit/audit.db < schema.sql when DB exists | Overwrites existing data |
Rule: If .audit/audit.db exists, ONLY use audit.py list, show, export, or INSERT operations. NEVER recreate.
Audit Flow
Interactive tracing of system flows with SQLite persistence. Supports multiple named flows per session, non-linear flows (branching/merging), and multi-format exports.
Organization Principles
Directory structure by purpose:
- Audits/Documentation/Compliance:
docs/audits/{name}-{YYYY-MM-DD}/ - Ideation/Brainstorming:
docs/ideation/{name}-{YYYY-MM-DD}.md(single file, no subdirectory unless artifacts needed) - Debugging/Incident Review:
docs/audits/{name}-{YYYY-MM-DD}/(same as audits — captures evidence) - Architecture Review:
docs/audits/{name}-{YYYY-MM-DD}/(same as audits — captures structural analysis)
Required files:
- INDEX.md (manifest, entry point)
- README.md (executive summary)
- {name}-audit.md (flow trace)
Lazy initialization: Create subdirectories only when artifacts exist
screenshots/network-traces/diagrams/code-samples/test-results/evidence/
Naming: {audit-name}-{type}.md
DB-First Discipline
Invariant: SQLite = sole source of truth. Context window: volatile, compacts without notice, hallucinates state.
🚨 CRITICAL: NEVER DESTROY EXISTING DATA
- If
.audit/audit.dbexists → it contains irreplaceable audit history - NEVER run
initwhen DB exists — uselistto see what's there - NEVER delete, drop, or recreate — only append
Constraints:
| Operation | Rule | Blocked rationalization |
| ----------- | ----------------------------------------------------------------------------------------- | ------------------------------------ |
| Entry | Read schema.sql FIRST, check if DB exists SECOND | "I'll just start working" |
| Init | ONLY if .audit/audit.db does NOT exist | "Let me reinitialize to start fresh" |
| Schema | Read schema.sql BEFORE any SQLite command — understand tables, constraints, views first | "I know the schema from context" |
| Write | INSERT each tuple/edge/finding before moving to the next code location | "I'll batch-insert at the end" |
| Read | SELECT from DB before referencing tuple IDs, counts, or flow structure | "I remember the flow so far" |
| Export | audit.py export only — never generate mermaid/markdown from context | "Let me generate mermaid directly" |
| Resume | audit.py show <session> before any operation that references prior tuples | "I have the full trace in context" |
| Reference | Query tuple IDs from DB — IDs are DB-assigned, never inferred | "The tuple ID should be N" |
| Default | When uncertain of flow state → query DB before proceeding | _(any unlisted rationalization)_ |
Checkpoint: Every 5 tuples → audit.py show <session> <flow>
Interactive Workflow - ALWAYS ASK USER
1. Session Start - Ask:
Name: ___
Purpose: security-audit | documentation | compliance | ideation | brainstorming | debugging | architecture-review | incident-review
Description: ___ (optional)
Initialize directory immediately. Lazily create subdirectories when artifacts are generated.
2. Granularity - Ask:
[fine] Function-level trace (~50-200 tuples)
Use: Security audits, debugging
[coarse] Boundary-level trace (~10-30 tuples)
Use: Documentation, high-level flows
Choose: fine / coarse
3. During Trace:
Ask at decision points: trace deeper? mark concern? add finding (severity)? note?
4. On Export:
Ask format: json | yaml | md | mermaid | all
Post-export: Generate INDEX.md manifest. Organize artifacts by type. Prune empty directories.
Quick Reference
| Command | Purpose |
| ------------------------------------ | ---------------------------------------------- |
| /audit-flow start | New session (name, purpose, granularity) |
| /audit-flow flow {name} | Add new flow to session |
| /audit-flow add {layer} {desc} | Add tuple to current flow |
| /audit-flow link {from} {to} {rel} | Create edge (supports conditions for branches) |
| /audit-flow finding {desc} | Record finding |
| /audit-flow show | View session/flow details |
| /audit-flow export | Export (json/yaml/md/mermaid) |
| /audit-flow git-setup | Configure git merge/diff drivers (once) |
Layers: CODE | API | NETWORK | AUTH | DATA
Relations: TRIGGERS | READS | WRITES | VALIDATES | TRANSFORMS | BRANCHES | MERGES
Semantic Rules for Relations
| Relation | Meaning | Use When | NOT For |
| ------------ | ---------------------------- | --------------------------------------------- | ----------------------------- |
| TRIGGERS | A causes B to execute | Function calls, event handlers, HTTP requests | Static observations |
| READS | A consumes data from B | Cookie reads, DB queries, config lookups | Mutations |
| WRITES | A mutates data in B | Cookie writes, DB inserts, state updates | Read-only access |
| VALIDATES | A checks/verifies B | Auth checks, input validation, expiry checks | Chaining analyst observations |
| TRANSFORMS | A converts/maps data for B | Token exchange, response formatting | Unrelated processing |
| BRANCHES | A has conditional paths | if/else, switch, error vs success | Must have condition label |
| MERGES | Multiple paths converge at B | Parallel paths rejoin, error recovery | Single-path flow |
CRITICAL: BRANCHES Must Have Conditions. Every BRANCHES edge requires a condition describing which path. Example: BRANCHES [token expired] vs BRANCHES [token valid].
Observations vs Flow Steps
Flow steps = things the SYSTEM DOES (function calls, data reads, network requests). Verified by tracing code.
Observations = things the ANALYST NOTES (missing features, potential risks). Record as findings, not tuples.
Wrong pattern:
T50 "NO cross-tab sync" ← observation, not a system action
T51 "React state NOT shared" ← observation
T50 --VALIDATES--> T51 ← chaining observations as flow
Correct pattern:
-- Record as finding instead:
INSERT INTO findings (flow_id, session_id, severity, category, description)
VALUES (?, ?, 'medium', 'state-management',
'No cross-tab sync: React state not shared across tabs');
Rule: NEVER chain observations with VALIDATES. If describing what the system DOESN'T do, use a finding.
Data Model
Session (audit container)
└── Flow (named DAG with entry point)
└── Tuple (node: layer + action + subject)
└── Edge (relation + optional condition)
Storage & CLI
# Core
python .claude/skills/audit-flow/scripts/audit.py init # Initialize DB
python .claude/skills/audit-flow/scripts/audit.py list # List sessions
python .claude/skills/audit-flow/scripts/audit.py show <session> # Show flows
python .claude/skills/audit-flow/scripts/audit.py show <session> <flow> # Show flow details
python .claude/skills/audit-flow/scripts/audit.py export <session> # Export all
python .claude/skills/audit-flow/scripts/audit.py export <session> -f <flow> # Export one flow
python .claude/skills/audit-flow/scripts/audit.py validate <session> # Validate flows
# Git integration
python .claude/skills/audit-flow/scripts/audit.py git-setup # Configure merge/diff drivers (once)
python .claude/skills/audit-flow/scripts/audit.py db-merge %O %A %B # Git merge driver (auto-called)
# CSV backup/portability (optional)
python .claude/skills/audit-flow/scripts/audit.py csv-export # DB → .audit/csv/*.csv
python .claude/skills/audit-flow/scripts/audit.py csv-import # .audit/csv/*.csv → DB
python .claude/skills/audit-flow/scripts/audit.py csv-merge <theirs_dir> # Merge two CSV sets
Non-Linear Flows
Branching: One tuple → multiple outgoing edges with conditions
INSERT INTO edges (from_tuple, to_tuple, relation, condition)
VALUES (5, 6, 'BRANCHES', 'token valid'),
(5, 7, 'BRANCHES', 'token expired');
Merging: Multiple tuples → one tuple
INSERT INTO edges (from_tuple, to_tuple, relation)
VALUES (6, 8, 'TRIGGERS'),
(9, 8, 'MERGES'); -- refresh path merges back
Files
- [scripts/audit.py](scripts/audit.py) - CLI for all commands (init, list, show, export, validate, db-merge, git-setup, csv-\*)
- [COMMANDS.md](COMMANDS.md) - Detailed SQL reference
- [EXAMPLES.md](EXAMPLES.md) - Full examples with non-linear flows
- [schema.sql](schema.sql) - Database schema
.gitattributes- Git merge/diff driver config for audit.db
Git Context
Capture on session start: commit hash, branch, working tree status. Include in all exports.
Mermaid Validation
Run python .claude/skills/audit-flow/scripts/audit.py validate <session> before export.
| Check | Severity | Description |
| -------------------------- | -------- | ----------------------------------------------- |
| BRANCHES without condition | ERROR | Every BRANCHES edge needs a condition label |
| Node count >= 60 | ERROR | Split into sub-flows |
| Node count >= 40 | WARN | Consider splitting |
| Orphan nodes | WARN | Node with no edges (disconnected) |
| Duplicate labels | WARN | Same action text without subject disambiguation |
| No entry point | WARN | All nodes have incoming edges |
Post-export features (automatic):
- Step numbers: BFS topological order from entry point (
1. action,2. action) - Entry point: Stadium shape with green styling
- Edge arrows:
-->solid (TRIGGERS/VALIDATES/TRANSFORMS/BRANCHES/MERGES),-.->dotted (READS),==>thick (WRITES) - Observations: Separated into dashed-border OBSERVATIONS subgraph
- Direction:
--direction LRflag for horizontal layouts
Diagram Readability Requirements
All diagrams MUST be produced by audit.py export. Never hand-craft mermaid. The exporter enforces:
- Entry point marker — Green stadium-shape node
([label]):::entryPoint - Step numbers — BFS topological order:
1. action,2. action,3. action - Legend block — classDef styles for entryPoint, concern, observation
- Observation separation — Concern-only chains go to OBSERVATIONS subgraph, not main flow
- Label safety — HTML entities for
(),"",<>,|,[]characters (auto-sanitized)
Reading flow must be obvious. A reader opening the diagram cold must immediately see:
- WHERE to start (green entry node)
- WHAT ORDER to read (step numbers)
- WHICH PATH is happy vs error (branch conditions on edges)
- WHAT THE COLORS MEAN (legend)
Node label rules:
- Use concrete nouns/verbs:
handleCallback(),exchangeCodeForTokens() - NOT bare verbs: ~~"Configure"~~, ~~"Select"~~, ~~"Enable"~~
- Disambiguate duplicates: auto-suffixed with subject when action repeats
Size limits:
- 40+ nodes → warning, consider splitting
- 60+ nodes → error, MUST split into sub-flows
- If flow has 5+ independent sub-flows → split by purpose
Git Workflow — Custom Merge Driver
Problem: SQLite is binary — git merge can't auto-resolve .audit/audit.db.
Solution: Custom git merge driver. audit.db stays in git (small, single file). On conflict, git calls audit.py db-merge to auto-merge using SQL.
One-Time Setup
python .claude/skills/audit-flow/scripts/audit.py git-setup
This configures (in .git/config):
- Merge driver:
merge.sqlite-audit— callsaudit.py db-merge %O %A %Bon conflict - Diff driver:
diff.sqlite—sqlite3 .dumpfor readablegit diffoutput
Also requires .gitattributes (already in repo):
.audit/audit.db diff=sqlite merge=sqlite-audit
How It Works
- You commit
audit.dbnormally —git add .audit/audit.db && git commit git diffshows SQL text (via textconv)- On
git mergewith conflict → git calls the merge driver automatically - Driver opens both DBs, merges sessions by name (later
updated_atwins), remaps IDs - Result written to ours — merge completes cleanly
Merge Strategy
| Table | Merge Key | Conflict Resolution |
| -------- | --------------------------------------- | --------------------------------- |
| sessions | name (unique) | Keep later updated_at |
| flows | (session_name, flow_name) | Follow parent session winner |
| tuples | Parent flow | All tuples from winning flow kept |
| edges | Both endpoint tuples | Kept if both endpoints survive |
| findings | (session_name, category, description) | Dedup by content |
All INTEGER PKs remapped sequentially. Foreign keys updated.
CSV Backup (Optional)
CSV export/import still available for portability and backup:
python .claude/skills/audit-flow/scripts/audit.py csv-export # DB → .audit/csv/*.csv (QUOTE_ALL)
python .claude/skills/audit-flow/scripts/audit.py csv-import # CSV → DB (recreates from scratch)
Output Quality
Principles:
- ASCII sequence diagrams for complex flows
- Side-by-side tables for alternatives
- Real code from traced files with
file:linereferences - What/Why/Example pattern
- No generic templates
Completion Checklist
- [ ] Directory exists with ISO date suffix
- [ ] INDEX.md manifest generated
- [ ] README.md (executive summary)
- [ ] Naming convention:
{name}-{type}.md - [ ] Artifacts in typed subdirectories (lazy init)
- [ ] Git context captured
- [ ] Git merge driver configured (
audit.py git-setup) - [ ] No orphaned files
- [ ] Diagrams pass
audit.py validate
Anti-Patterns
Flat structure, empty directories, orphan nodes, unlabeled branches, generic identifiers, missing git context, no manifest, hand-crafted mermaid, bare-verb labels.
想直接用这个技能?
本站把开放许可(MIT / Apache 等)的技能按仓库打包整理到网盘,点一下转存到你自己的网盘,不用一个个从 GitHub 拉。许可未声明的技能只给原始仓库链接,不打包。