GhostAudit
English · 中文 · 日本語 · 한국어 · Русский · Deutsch
Tamper-evident filesystem auditing for multi-project workspaces. Hashes every file with SHA-256, tracks changes across runs, generates a per-project AUDIT.md, and seals findings in a Merkle tree. Optional encrypted evidence capsules for SOC 2, HIPAA, and AI-provenance workflows.
Stdlib-only core. No pip dependencies unless you enable encrypted capsules.
Quick Start
pip install ghostaudit
# Run a full audit (inventory + index + diff)
ghostaudit --mode full --workspace /path/to/workspace
# Run the daily pipeline (hash → compare → audit or sleep)
ghostaudit --mode daily --workspace /path/to/workspace
# Just update project audits
ghostaudit --mode update_audits --workspace /path/to/workspace
# Preview audit changes without writing
python -m workspace_audit.update_audits --workspace /path/to/workspace --dry-run
Tools
| Tool | Purpose |
|---|---|
run_audit.py |
Orchestrator — runs any mode via --mode flag |
daily_audit.py |
Daily runner — hash, compare, full audit or sleep |
hash_manifest.py |
SHA-256 hashes every file, compares to previous manifest |
generate_inventory.py |
Scans workspace, classifies items, detects secrets |
build_index.py |
Generates consolidated AUDIT_INDEX.md from all data |
diff_audits.py |
Compares current vs previous snapshots, tracks changes |
update_audits.py |
Auto-generates and versions per-project AUDIT.md files |
Modes
run_audit.py --mode <mode>
| Mode | What it does |
|---|---|
full |
inventory → index → diff |
daily |
hash → compare → if changes: full + update_audits + daily report; if no changes: sleep |
inventory_only |
Just scan filesystem metadata |
index_only |
Regenerate AUDIT_INDEX.md from existing data |
diff_only |
Compare current to previous snapshot |
hash_only |
Hash files and compare to previous manifest |
update_audits |
Generate/update per-project AUDIT.md files |
Pipeline Flow
daily_audit.py
├── hash_manifest.py → audit/manifests/{timestamp}.json
│ └── compare → audit/manifests/latest_result.json
│
├── [if changes detected]
│ ├── generate_inventory.py → audit/inventory.json
│ ├── build_index.py → administration/AUDIT_INDEX.md
│ ├── diff_audits.py → audit/history/diffs/{timestamp}.json
│ ├── update_audits.py → {project}/AUDIT.md (versioned)
│ └── daily report → audit/daily/{date}.md
│
└── [if no changes]
└── log "no_changes" → audit/daily/daily_log.jsonl
Configuration
Create audit.config.json in your workspace root (optional — all settings have defaults):
{
"owner": "auto",
"composite_projects": ["my-monorepo"],
"force_audit_subdirs": ["legacy-api", "worker"],
"skip_dirs": [
"node_modules", ".git", "target", ".next", "dist", "__pycache__",
".pytest_cache", "venv", ".venv", "vendor", ".mypy_cache"
],
"admin_dir": "administration",
"audit_dir": "audit",
"version_audits": true,
"generate_sub_audits": true
}
| Setting | Default | Description |
|---|---|---|
owner |
"auto" |
Owner name in AUDIT.md. "auto" reads from git config user.name |
composite_projects |
[] |
Projects that should always be treated as composite (per-subdir audits) |
force_audit_subdirs |
[] |
Subdirectory names to audit even if they don't have build configs |
skip_dirs |
(see above) | Directories to skip when scanning |
admin_dir |
"administration" |
Where to write AUDIT_INDEX.md |
audit_dir |
"audit" |
Where to write inventory, manifests, and history |
version_audits |
true |
Archive old AUDIT.md before overwriting |
generate_sub_audits |
true |
Generate per-component audits for composite projects |
Composite Projects
Projects with 2+ subdirectories containing build configs (package.json, Cargo.toml, etc.) are automatically detected as composite. For each composite project:
- Each sub-component gets its own
{component}/AUDIT.md - The parent gets a summary
AUDIT.mdwith a component table - Add directories to
force_audit_subdirsin config if they lack standard build configs
Versioning
When version_audits is true (default), the old AUDIT.md is archived to {project}/audits/AUDIT-{date}.md before being overwritten. Same-day re-runs are detected and don't create duplicate archives.
Scheduling (Windows)
@echo off
cd /d C:\path\to\workspace
python tools\audit\daily_audit.py --workspace C:\path\to\workspace >> audit\daily\scheduler.log 2>&1
schtasks /create /tn "WorkspaceAudit" /tr "C:\path\to\schedule_daily.bat" /sc daily /st 04:00 /f
Scheduling (Linux/macOS)
# crontab -e
0 4 * * * cd /path/to/workspace && python tools/audit/daily_audit.py >> audit/daily/scheduler.log 2>&1
Output Structure
workspace/
├── audit/
│ ├── inventory.json # Current inventory
│ ├── inventory_summary.json # Rollup stats
│ ├── findings.json # Tracked findings
│ ├── manifests/ # Hash manifests
│ │ ├── {timestamp}.json
│ │ └── latest_result.json # Last comparison result
│ ├── history/
│ │ ├── inventory/ # Historical snapshots
│ │ ├── findings/
│ │ └── diffs/ # Change reports
│ └── daily/
│ ├── {date}.md # Daily reports
│ ├── daily_log.jsonl # Run log
│ └── scheduler.log # Cron/scheduler output
├── administration/
│ └── AUDIT_INDEX.md # Consolidated index
├── project-a/
│ ├── AUDIT.md # Auto-generated audit
│ └── audits/
│ └── AUDIT-2026-03-22.md # Versioned archive
└── audit.config.json # Configuration (optional)
GitHub Action
Use GhostAudit as a GitHub Action to get findings as GitHub Code Scanning alerts in pull requests and the repository Security tab.
Basic usage
- uses: adam-scott-thomas/ghostaudit@v1
with:
profiles: 'security'
fail-on: 'CRITICAL'
upload-sarif: 'true'
Full workflow example
name: Workspace Audit
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
schedule:
- cron: '0 4 * * *'
permissions:
security-events: write
contents: read
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Workspace Audit
id: audit
uses: adam-scott-thomas/ghostaudit@v1
with:
profiles: 'security,soc2'
fail-on: 'CRITICAL'
upload-sarif: 'true'
- name: Print summary
run: |
echo "Findings: ${{ steps.audit.outputs.findings-count }}"
echo "Critical: ${{ steps.audit.outputs.critical-count }}"
echo "High: ${{ steps.audit.outputs.high-count }}"
Inputs
| Input | Default | Description |
|---|---|---|
profiles |
security |
Comma-separated audit profiles (security, feature, soc2, quality) |
project |
(all) | Specific project to audit |
format |
sarif |
Output format (sarif, json, csv, markdown) |
fail-on |
never |
Fail if findings at this severity or above (CRITICAL, HIGH, MEDIUM, LOW, never) |
upload-sarif |
true |
Upload SARIF to GitHub Code Scanning |
python-version |
3.12 |
Python version to use |
Outputs
| Output | Description |
|---|---|
findings-count |
Total number of findings |
critical-count |
Number of CRITICAL findings |
high-count |
Number of HIGH findings |
sarif-file |
Path to SARIF output file |
report-file |
Path to report output file |
SARIF integration
When upload-sarif is true (the default), findings are uploaded to GitHub Code Scanning via the github/codeql-action/upload-sarif action. This requires the security-events: write permission. Findings appear in the repository's Security tab and as annotations on pull requests.
Requirements
- Python 3.10+
- Git (for owner detection and git status checks)
- No pip dependencies for the core — stdlib only
cryptography>=42.0only if you enable encrypted evidence capsules (pip install ghostaudit[capsule])
License
GhostAudit is licensed under the PolyForm Shield License 1.0.0. This is a source-available commercial-restrictive license. You may use, modify, and redistribute GhostAudit for any purpose, including internal enterprise use, except to build a product or service that competes with GhostAudit or with a product GhostLogic LLC provides using GhostAudit. See LICENSE for the full terms.
Copyright GhostLogic LLC.
Release files for ghostaudit 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ghostaudit-1.2.0.tar.gz | 115.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ghostaudit-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 246.4 kB
Release files / ghostaudit-1.2.0.tar.gz
| Download URL | ghostaudit-1.2.0.tar.gz |
|---|---|
| Size | 115.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fe13034131e1721afdc8da481e441ede88f6f54d72301eb33eae21b364eb99c6
|
|
BLAKE2b-256 checksum How to use checksums |
5cbc886e5a3e9375bc0b975381dc2c9fe97a6bee892de8c204437a5f8c928f34
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / ghostaudit-1.2.0-py3-none-any.whl
| Download URL | ghostaudit-1.2.0-py3-none-any.whl |
|---|---|
| Size | 131.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4a901eef651f3bfedccf5cdd948d1b402ef42689c097bf1759c294f336d0528
|
|
BLAKE2b-256 checksum How to use checksums |
35e7b85268c0681e4c2b226bb07a5f0540500b89f185618f3bfbbab35e5b9cd2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|