- Posted on
- • Artificial Intelligence
Artificial Intelligence Compliance Reporting
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Bash-first AI Compliance Reporting: Practical, Auditable, and Automatable
Artificial intelligence isn’t just about accuracy and speed anymore—it's about trust, transparency, and auditability. New standards and regulations increasingly expect teams to document model provenance, data lineage, risk controls, and usage. The good news: you can build a robust compliance reporting workflow with the tools you already know—Bash, jq, sqlite3, and a few small helpers.
This guide shows how to implement AI compliance reporting on Linux using shell scripts and common CLI tools. You’ll learn what to record, how to record it, and how to generate auditable reports automatically.
Why this matters now
Regulators and customers are asking for transparency (e.g., model versions, datasets, and risk mitigations).
Incidents are inevitable; reproducible runs and clear audit trails shorten time-to-resolution.
Standard frameworks (e.g., ISO/IEC 42001 AI management systems, NIST AI RMF) point to governance, documentation, and controls.
You don’t need to centralize everything in a heavyweight tool to start—Bash + JSON + SQLite scales surprisingly far.
What a useful AI compliance report contains
Inventory: models, data sources, code versions, dependencies, runtime environment.
Provenance: who changed what, when, and how (commit hashes, dataset digests).
Controls: PII redaction, license checks, policy exceptions, approval references.
Usage & outcomes: prompts, outputs, decisions, key metrics, and incident notes.
Below we build these with a Bash-first toolkit.
Prerequisites (install these first)
- jq (JSON), sqlite3 (lightweight database), ripgrep (fast scanning), git (versioning)
Ubuntu/Debian (apt):
sudo apt update
sudo apt install -y jq sqlite3 ripgrep git
Fedora/RHEL/CentOS Stream (dnf):
sudo dnf install -y jq sqlite ripgrep git
openSUSE/SLE (zypper):
sudo zypper refresh
sudo zypper install -y jq sqlite3 ripgrep git
Tip: The sqlite package name is “sqlite3” on Debian/Ubuntu/openSUSE and “sqlite” on Fedora/RHEL/CentOS, but all provide the sqlite3 CLI.
Step 1: Create an AI System Bill of Materials (AI-SBOM)
Capture the who/what/where of your run so it’s reproducible and reviewable. This script produces a JSON file (ai_sbom.json) describing model, datasets, code commit, dependencies, and OS metadata.
Save as ai_sbom.sh and make it executable:
#!/usr/bin/env bash
set -euo pipefail
# Inputs (set these for your run)
MODEL_ID="${MODEL_ID:-meta-llama/Llama-3-8B}"
MODEL_REV="${MODEL_REV:-2024-06-01}"
DATASET_DIR="${DATASET_DIR:-./data}"
RUN_PURPOSE="${RUN_PURPOSE:-fine-tune-evaluation}"
OUTPUT="${OUTPUT:-ai_sbom.json}"
dataset_digest() {
# Deterministic digest of all files under DATASET_DIR
# Ignores file order and directory metadata
find "$DATASET_DIR" -type f -print0 \
| sort -z \
| xargs -0 sha256sum \
| sha256sum \
| awk '{print $1}'
}
git_commit="$(git rev-parse --short=12 HEAD 2>/dev/null || echo "no-git")"
pip_freeze="$(python3 -m pip freeze 2>/dev/null || true)"
pip_hash="$(printf '%s\n' "$pip_freeze" | sha256sum | awk '{print $1}')"
os_name="$(. /etc/os-release; echo "$NAME")"
os_version="$(. /etc/os-release; echo "$VERSION")"
kernel="$(uname -r)"
dataset_hash="$(dataset_digest)"
jq -n \
--arg ts "$(date -Iseconds)" \
--arg model_id "$MODEL_ID" \
--arg model_rev "$MODEL_REV" \
--arg dataset_dir "$DATASET_DIR" \
--arg dataset_hash "$dataset_hash" \
--arg git_commit "$git_commit" \
--arg pip_hash "$pip_hash" \
--arg pip_freeze "$pip_freeze" \
--arg os_name "$os_name" \
--arg os_version "$os_version" \
--arg kernel "$kernel" \
--arg run_purpose "$RUN_PURPOSE" \
'{
sbom_version: "1.0",
timestamp: $ts,
run_purpose: $run_purpose,
model: { id: $model_id, revision: $model_rev },
dataset: { path: $dataset_dir, sha256_tree: $dataset_hash },
code: { git_commit: $git_commit },
environment: { os: $os_name, os_version: $os_version, kernel: $kernel },
dependencies: { pip_hash: $pip_hash, pip_freeze: ($pip_freeze | split("\n")) }
}' > "$OUTPUT"
echo "Wrote $OUTPUT"
Run it:
chmod +x ai_sbom.sh
MODEL_ID="my-org/my-llm" MODEL_REV="v0.9.2" DATASET_DIR="./data" RUN_PURPOSE="pilot-audit" ./ai_sbom.sh
What you get: a self-contained JSON snapshot tying your model, data, code, and environment to a specific run.
Step 2: Log prompts and responses (with redaction) to SQLite
Store an audit trail that balances transparency and privacy. This wrapper records structured events in ai_audit.db and redacts common sensitive patterns.
Initialize the database:
sqlite3 "$HOME/ai_audit.db" <<'SQL'
PRAGMA journal_mode=WAL;
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY,
ts TEXT NOT NULL,
user TEXT,
tool TEXT,
model TEXT,
input TEXT,
output TEXT,
tags TEXT
);
CREATE INDEX IF NOT EXISTS idx_events_ts ON events(ts);
CREATE INDEX IF NOT EXISTS idx_events_user ON events(user);
CREATE INDEX IF NOT EXISTS idx_events_model ON events(model);
SQL
Wrapper script ai_call.sh:
#!/usr/bin/env bash
set -euo pipefail
DB="${AI_AUDIT_DB:-$HOME/ai_audit.db}"
USER_NAME="${AI_USER:-${USER:-unknown}}"
TOOL="${TOOL_NAME:-bash-wrapper}"
MODEL="${MODEL_ID:-unknown}"
TAGS="${AI_TAGS:-production}"
redact() {
sed -E \
-e 's/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/[REDACTED_EMAIL]/g' \
-e 's/\b([0-9]{3}[- ]?[0-9]{2}[- ]?[0-9]{4})\b/[REDACTED_ID]/g' \
-e 's/\b([0-9]{13,19})\b/[REDACTED_NUMBER]/g'
}
sql_escape() {
# Escape single quotes for SQL insertion
printf "%s" "$1" | sed "s/'/''/g"
}
prompt="$*"
[ -n "$prompt" ] || { echo "Usage: $0 'your prompt here'"; exit 2; }
# Example call: replace this with your actual model/API invocation
# For demo, we just echo a canned response
raw_out="This is a demo response for: $prompt"
input_redacted="$(printf "%s" "$prompt" | redact)"
output_redacted="$(printf "%s" "$raw_out" | redact)"
ts="$(date -Iseconds)"
sql="INSERT INTO events (ts, user, tool, model, input, output, tags)
VALUES (
'$(sql_escape "$ts")',
'$(sql_escape "$USER_NAME")',
'$(sql_escape "$TOOL")',
'$(sql_escape "$MODEL")',
'$(sql_escape "$input_redacted")',
'$(sql_escape "$output_redacted")',
'$(sql_escape "$TAGS")'
);"
sqlite3 "$DB" "$sql"
echo "Logged event at $ts"
Use it:
chmod +x ai_call.sh
AI_TAGS="pilot,redacted" MODEL_ID="my-org/my-llm:v0.9.2" ./ai_call.sh "Summarize customer emails from support@acme.example"
Query it:
sqlite3 "$HOME/ai_audit.db" "SELECT ts,user,model,substr(input,1,60)||'…' as input FROM events ORDER BY ts DESC LIMIT 5;"
Note: Expand redaction rules to match your policies. For highly sensitive contexts, consider hashing or tokenization.
Step 3: Scan for license and PII risk with ripgrep
You can catch many issues early by scanning repositories and data directories for risky strings (e.g., non-commercial licenses, suspected PII).
License/terms scan:
RGOPTS="--ignore-case --line-number --hidden --no-messages"
rg $RGOPTS -e 'GPL|AGPL|LGPL|CC[- ]?BY|non[- ]?commercial|no[- ]?derivative|proprietary' ./ > license_scan.txt || true
echo "License hits: $(wc -l < license_scan.txt)"
PII heuristic scan (tune these for your domain):
rg $RGOPTS -e '\b[0-9]{3}[- ]?[0-9]{2}[- ]?[0-9]{4}\b' -e '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}' ./data > pii_scan.txt || true
echo "PII hits: $(wc -l < pii_scan.txt)"
Summarize to JSON for reporting:
jq -n \
--arg ts "$(date -Iseconds)" \
--arg license_hits "$(wc -l < license_scan.txt)" \
--arg pii_hits "$(wc -l < pii_scan.txt)" \
'{
timestamp: $ts,
scans: {
license_hits: ( $license_hits | tonumber ),
pii_hits: ( $pii_hits | tonumber )
}
}' > risk_summary.json
Store scan outputs alongside each run so auditors can trace decisions.
Step 4: Generate a monthly compliance report (Markdown + CSV)
Combine the AI-SBOM, audit logs, and risk scans into a human-readable report. This script emits a Markdown report with useful rollups.
report.sh:
#!/usr/bin/env bash
set -euo pipefail
DB="${AI_AUDIT_DB:-$HOME/ai_audit.db}"
SBOM="${SBOM_FILE:-ai_sbom.json}"
RISK="${RISK_FILE:-risk_summary.json}"
OUTDIR="${OUTDIR:-./reports}"
MONTH="${MONTH:-$(date +%Y-%m)}" # e.g., 2026-07
mkdir -p "$OUTDIR"
# Summary queries
total_events=$(sqlite3 "$DB" "SELECT COUNT(*) FROM events WHERE ts LIKE '$MONTH%';")
by_user=$(sqlite3 -header -csv "$DB" "SELECT user, COUNT(*) as events FROM events WHERE ts LIKE '$MONTH%' GROUP BY user ORDER BY events DESC;")
by_model=$(sqlite3 -header -csv "$DB" "SELECT model, COUNT(*) as events FROM events WHERE ts LIKE '$MONTH%' GROUP BY model ORDER BY events DESC;")
model_id=$(jq -r '.model.id' "$SBOM" 2>/dev/null || echo "unknown")
model_rev=$(jq -r '.model.revision' "$SBOM" 2>/dev/null || echo "unknown")
dataset_hash=$(jq -r '.dataset.sha256_tree' "$SBOM" 2>/dev/null || echo "unknown")
git_commit=$(jq -r '.code.git_commit' "$SBOM" 2>/dev/null || echo "unknown")
os="$(jq -r '.environment.os+" "+.environment.os_version' "$SBOM" 2>/dev/null || echo "unknown")"
risk_license=$(jq -r '.scans.license_hits' "$RISK" 2>/dev/null || echo "0")
risk_pii=$(jq -r '.scans.pii_hits' "$RISK" 2>/dev/null || echo "0")
report_md="$OUTDIR/report-$MONTH.md"
cat > "$report_md" <<EOF
# AI Compliance Report ($MONTH)
## Run Inventory
- Model: $model_id ($model_rev)
- Dataset SHA256 (tree): $dataset_hash
- Code commit: $git_commit
- Environment: $os
## Usage Summary
- Total logged events this month: $total_events
### Events by user
\`\`\`
$by_user
\`\`\`
### Events by model
\`\`\`
$by_model
\`\`\`
## Risk Summary
- License scan hits: $risk_license
- PII scan hits: $risk_pii
## Notes
- Ensure exceptions/approvals are linked in your change log.
- Verify redaction coverage if PII hits > 0.
EOF
echo "Wrote $report_md"
# Also emit CSV rollups for BI tools
printf "%s\n" "$by_user" > "$OUTDIR/events_by_user-$MONTH.csv"
printf "%s\n" "$by_model" > "$OUTDIR/events_by_model-$MONTH.csv"
echo "Wrote CSV rollups to $OUTDIR"
Run it:
chmod +x report.sh
SBOM_FILE=ai_sbom.json RISK_FILE=risk_summary.json ./report.sh
You now have a Markdown report you can archive or hand to auditors, plus CSVs for BI dashboards.
Step 5: Automate and archive (cron + integrity checks)
Set up a monthly job to generate and archive reports with integrity hashes.
Create archive script archive_reports.sh:
#!/usr/bin/env bash
set -euo pipefail
OUTDIR="${OUTDIR:-./reports}"
ARCHIVE_DIR="${ARCHIVE_DIR:-./archives}"
MONTH="${MONTH:-$(date +%Y-%m)}"
mkdir -p "$ARCHIVE_DIR"
tarball="$ARCHIVE_DIR/ai-compliance-$MONTH.tar.gz"
tar -czf "$tarball" -C "$OUTDIR" .
sha256sum "$tarball" > "$tarball.sha256"
echo "Archived $tarball and wrote SHA256"
Example crontab (edit with crontab -e):
# Generate report at 02:15 on the 1st of every month
15 2 1 * * SBOM_FILE=/path/ai_sbom.json RISK_FILE=/path/risk_summary.json AI_AUDIT_DB=/path/ai_audit.db /path/report.sh >> /var/log/ai_compliance.log 2>&1
# Archive at 02:20 on the 1st of every month
20 2 1 * * OUTDIR=/path/reports ARCHIVE_DIR=/path/archives /path/archive_reports.sh >> /var/log/ai_compliance.log 2>&1
Consider shipping archives to immutable storage (e.g., object store with retention policies). For tamper-evidence, keep SHA256 files separately or add digital signatures.
Real-world mini-example
A team fine-tunes an LLM on internal FAQs.
Before training, they run ai_sbom.sh to snapshot model version, dataset digest, and code commit.
Their CLI tools call ai_call.sh to log evaluation prompts/responses with redaction into ai_audit.db.
Nightly, ripgrep scans produce risk_summary.json.
Monthly, report.sh compiles everything into a Markdown report and CSVs; archive_reports.sh bundles and hashes the artifacts.
When Security asks, “Which model and dataset were used for customer-facing suggestions in June?” the team answers in minutes with a signed report and supporting logs.
Tips and extensions
Add policy fields: approver, ticket IDs, DPIA references, and exceptions to the SBOM or a policies.json file.
Expand redaction to cover your data types; consider regex libraries or preprocessors.
For multi-team setups, shard DBs per project, then union reports.
Pair SQLite with write-ahead logging (WAL) and backups; it’s resilient and easy to restore.
Integrate CI to block merges if license_scan.txt or pii_scan.txt exceed thresholds.
Conclusion and next steps
Compliance doesn’t have to be heavyweight. With a handful of Linux tools and disciplined scripting, you can deliver transparent, reproducible, and auditable AI workflows today.
Start by generating your first AI-SBOM with ai_sbom.sh.
Wrap your model calls with ai_call.sh to capture redacted audit events.
Add ripgrep scans and wire up report.sh + archive_reports.sh to run monthly.
Share the report with your stakeholders and iterate on gaps.
Have questions or want a hardened version of these scripts? Fork them, add your policies, and make compliance a first-class citizen in your Bash toolbox.