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.
Metadata
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 | Provenance | Actions |
|---|---|---|---|---|
| ghostaudit-1.2.0.tar.gz | 115.1 kB | Without provenance | Details for ghostaudit-1.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| ghostaudit-1.2.0-py3-none-any.whl | Python 3 | none | any | Details for ghostaudit-1.2.0-py3-none-any.whl |
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
|
Security for ghostaudit 1.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.