git-audit: 42-repo hygiene audit Aug 8 - credentials, sprawl, nesting

This commit is contained in:
root
2026-08-08 12:50:12 -04:00
parent ca402d3444
commit a269a17b1f
+364
View File
@@ -0,0 +1,364 @@
# Git Audit Report — IT Pro Partner Gitea Organization
**Date:** 2026-08-08
**Auditor:** Hermes Agent (automated)
**Scope:** git.itpropartner.com / ippadmin (all 42 remote repos + 59 local clones in `/root/projects/`)
---
## Summary Verdict
**The Gitea organization suffers from repo sprawl, weak hygiene, and live secrets in history.** Of 42 remote repos, 32 are single-commit documentation stubs. Only 34 repos show active development. The `itpp-infrastructure/docs/` folder is a flat grab-bag and needs structured nesting. 23 local-only repos lack any off-server backup. Credentials are embedded in plaintext across at least 2 repos (`scripts`, `hermes-recovery`). Consolidation, cleanup, and a hygiene push are overdue.
---
## Quick Answers to User's Two Questions
### 1. Should `itpp-infrastructure/docs/` have more nested folders?
**Yes, absolutely.** The current structure is:
```
docs/
backup-restore/ ← already nested (good)
legal/ ← already nested (good)
ops-portal/ ← already nested (good)
app2-caddyfile-audit-2026-07-21.md ← flat
client-katie-watts-design.md ← flat
cost-control-rollout-2026-07-24.md ← flat
git-audit-2026-08-07.md ← flat
infrastructure-gap-assessment-2026-08-04.md ← flat
key-inventory.md ← flat
mattermost-replacement-analysis.md ← flat
model-chain.md ← flat
project-log.md ← flat
projects-master-readme.md ← flat
super-search-cf-bypass.md ← flat
super-search-enhancement-plan.md ← flat
uptime-kuma-monitoring-plan.md ← flat
```
**14 flat files is too many.** Recommended restructuring:
```
docs/
audit/ ← git-audit reports, gap assessments
backup-restore/ ← (existing, keep)
clients/ ← client-katie-watts-design.md
infrastructure/ ← model-chain.md, cost-control-rollout, caddyfile-audit, key-inventory
legal/ ← (existing, keep)
monitoring/ ← uptime-kuma-monitoring-plan.md
ops-portal/ ← (existing, keep)
projects/ ← project-log.md, projects-master-readme.md
super-search/ ← cf-bypass, enhancement-plan
mattermost-replacement-analysis.md ← leave at top level (one-off)
```
This gives every file a clear home without over-nesting.
### 2. Are there too many top-level repos? Should they be consolidated?
**Yes — 42 repos is far too many for the actual workload.** Here's the breakdown:
| Category | Count | Action |
|----------|-------|--------|
| Active development repos | 34 | Keep (`itpp-infrastructure`, `hermes-skills`, `scripts`, `homelab`) |
| Single-commit documentation stubs | 32 | Consolidate into fewer repos |
| Empty repos | 1 | Delete (`auth` — no commits, no content) |
| MCP stub repos | 5 | Merge into one `mcp-catalog` repo |
| Duplicate/stale repos | 2 | Resolve (`itpp-infra` vs `itpp-infrastructure`, `cartmylist-repo` vs `cartmylist`) |
| Local-only (unbacked) | 23 | Push to Gitea or archive |
**Recommended consolidation:**
1. **Merge 4 MCP stubs** (`mcp-browser`, `mcp-email`, `mcp-filesystem`, `mcp-git`) into `mcp-servers/` as subdirectories
2. **Merge related business ideas** into a `project-ideas` monorepo:
- `apex-track`, `boxpilot`, `digital-signage`, `fleettracker360`, `gift-a-roast`, `hudu`, `launchcheck`, `mooresunnydaze`, `nvr-shield`, `osint-tool`, `shark-game`, `startup-studio`, `track-a-flock`, `personal-assistant`
3. **Merge related operational repos**: `disaster-recovery` + `backup-restore``disaster-recovery/` with `backup-restore/` subdir
4. **Merge website/docs stubs**: `itpropartner-website`, `content-creation-pipeline`, `ops-portal` → subdirectories in `itpp-infrastructure`
5. **Resolve** `itpp-infra` (stale, SSH-only, 1 commit) → archive; use `itpp-infrastructure` as primary
6. **Delete** `auth` (empty repo with `auth.db` — never committed)
7. **Keep as-is**: `itpp-infrastructure`, `hermes-skills`, `hermes-recovery`, `scripts`, `homelab`, `dre`, `verdicttank`, `voipsimplicity`, `voipsimplicity-manual`, `forefront-wireless-portal`, `super-search-business`, `model-fallback`, `unifi`, `unms`, `pipeline`, `super-search`
**Target:** ~1520 repos instead of 42.
---
## Detailed Findings
### Step 1 — Full Inventory
| Metric | Count |
|--------|-------|
| Remote repos on Gitea | 42 |
| Local clones in `/root/projects/` | 59 |
| On Gitea AND cloned locally | 36 |
| On Gitea but NOT cloned locally | 6 |
| Cloned locally but NOT on Gitea | 23 |
| Public repos | 30 |
| Private repos | 12 |
| Repos using `master` as default branch | 30 |
| Repos using `main` as default branch | 9 |
| Other (HEAD/detached) | 20 |
**Repos on Gitea but not cloned locally:** `cartmylist`, `mcp-browser`, `mcp-email`, `mcp-filesystem`, `mcp-git`, `super-search`
**Local-only repos (no remote — no off-server backup):** `assistant`, `auth`, `capabilities`, `hear-read`, `intelsight`, `intelsight-landing`, `internal`, `mockup`, `my-itpropartner-portal`, `ops`, `ops-v2-portal`, `osint`, `proposals`, `pry`, `research-search-mcp`, `schedule`, `shonuff`, `shonuff-caller`, `static`, `status`, `voice-previews`, `itpp-infra`, `cartmylist-repo`
### Step 2 — Per-Repo Deep Scan
#### Hygiene Check: `.gitignore` and `README.md`
| Status | Count |
|--------|-------|
| Has `.gitignore` | 8 of 59 (13.6%) |
| Has `README.md` | 56 of 59 (94.9%) |
**Repos missing `.gitignore`:** 51 repos. This is the single biggest hygiene gap.
**Repos missing `README.md`:** `cartmylist-repo`, `voipsimplicity-manual`, `auth`
#### Repos with Dirty Working Trees
| Repo | Dirty Files | Severity |
|------|-------------|----------|
| `hermes-skills` | 33 | **HIGH** — cache artifacts not committed |
| `hermes-recovery` | 26 | **HIGH** — uncommitted recovery scripts |
| `voipsimplicity-manual` | 11 | **MEDIUM** |
| `research-search-mcp` | 10 | **MEDIUM** |
| `auth` | 9 | **MEDIUM** |
| `digital-signage` | 6 | **LOW** |
| `itpp-infra` | 5 | **LOW** |
| `pipeline` | 5 | **LOW** |
| `disaster-recovery` | 4 | **LOW** |
| `mooresunnydaze` | 4 | **LOW** |
| `verdicttank` | 4 | **LOW** |
| `itpp-infrastructure` | 3 | **LOW** |
**13 repos** have uncommitted changes. `hermes-skills` (33 files) and `hermes-recovery` (26 files) are the worst offenders.
### Step 3 — Secrets Scan
**CRITICAL findings in 2 repos:**
#### `scripts` — 10 potential secrets
Real, hardcoded credentials found in Windows provisioning scripts:
```
+Password="LoveMyBoys73!"
+Password="Liberty4All!"
+Password="tire"
+Username="ippadmin"
+Username="liberty-admin"
```
These are active Windows admin credentials embedded in PowerShell unattend scripts. **This is a data breach risk.** If these repos ever go public or are cloned outside ITPP infrastructure, client credentials are exposed.
#### `hermes-recovery` — 8 potential secrets
Includes the Gitea API token used for this audit:
```
+TOKEN="1761daa2c537fb72b365e54619208329d8e3ad33"
+TELEGRAM_BOT_TOKEN="8359374835:***"
+password="K3E1ZZWvHDu0q8ZmoBCAhzKUZawEapdGBlbaPME1sOTKgGk9FCuYS"
+token = "Ta9f9d1b462271a2f4-8d63a3f025eb89451edb16f2308c2e40"
```
The Gitea token itself is committed. This means `hermes-recovery` as a public repo exposes admin credentials.
#### `hermes-skills` — 15 potential hits
Most are false positives (example values, `process.env.` references, placeholder text). One real hit: a Comfy CLI API key in a SKILL.md.
### Step 4 — Structural Checks
#### Remote URL Audit
| Remote Type | Count | Action |
|-------------|-------|--------|
| HTTPS to Gitea | 36 | OK |
| GitHub (upstream) | 1 | OK (`msp-claude-skills`) |
| SSH to Gitea | 2 | **FIX**`itpp-infra`, `cartmylist-repo` |
| No remote | 23 | **FIX** — local-only, no backup |
`itpp-infra` uses `git@git.itpropartner.com:ippadmin/itpp-infra.git` (SSH) — this repo has no corresponding HTTPS clone and appears to be a stale/abandoned repo (1 commit, 5 dirty files).
`cartmylist-repo` (local) vs `cartmylist` (Gitea) is a naming mismatch. The local clone has an SSH remote to what is likely a different repo.
#### Branch Naming
- **30 repos use `master`** — industry standard is now `main`
- **9 repos use `main`**
- **20 repos have detached HEAD or no commits**
**Branch mismatch:** `itpp-infrastructure` has `main` locally but `master` on Gitea. This means the remote may have both branches.
#### Large Files
| Repo | File | Size |
|------|------|------|
| `hermes-skills` | `.hub/index-cache/hermes-index.json` | 38.9 MB |
| `hermes-skills` | `.curator_backups/2026-07-12T15-48-44Z/skills.tar.gz` | 2.7 MB |
Both are cache artifacts that should be in `.gitignore`, not tracked.
#### Public vs Private
**30 of 42 repos (71%) are public.** This is a concern because:
- `scripts` contains client admin passwords — **public**
- `hermes-recovery` contains Gitea admin token — **public**
- Many repos with sensitive infrastructure details are public
### Step 5 — Commit Quality
#### Commit Message Quality
| Pattern | Count | Assessment |
|---------|-------|------------|
| `Initial commit — YYYY-MM-DD` | 16 | Poor — conveys nothing |
| `Update YYYY-MM-DD — root` | 5 | Meaningless |
| `Initial: <project name>` | 8 | Barely adequate |
| Descriptive conventional commits | 4 | Good (`homelab`, `verdicttank`, `forefront-wireless-portal`) |
**32 repos have only 1 commit** — these are documentation stubs, not developed projects.
#### Active vs Abandoned
| Status | Criteria | Repos |
|--------|----------|-------|
| **Active** | 3+ commits, recent activity | `itpp-infrastructure` (52), `scripts` (11), `homelab` (6), `forefront-wireless-portal` (5), `dre` (4), `verdicttank` (4), `personal-assistant` (3), `super-search-business` (3), `voipsimplicity` (3) |
| **Stub** | 12 commits, last push July 2025 | 32 repos |
| **Abandoned** | No commits or stale >3 months | `itpp-infra`, `auth`, `cartmylist-repo` |
### Step 6 — Local-Only Repos
23 repos in `/root/projects/` have no remote. Breakdown:
| Category | Repos | Action |
|----------|-------|--------|
| Uncommitted stubs (0 commits) | 17 | Push to Gitea or archive |
| Has commits, no remote | 1 (`shonuff-caller`) | Push to Gitea |
| Stale noise | 5 | Archive and delete (`auth`, `itpp-infra`, `cartmylist-repo`, etc.) |
The 17 repos with 0 commits and only detached HEAD are effectively just directories with a `.git` folder — not real repos. They should be either pushed as proper repos or archived.
---
## Prioritized Action Plan
### 🔴 Immediate (This Week)
| # | Action | Severity |
|---|--------|----------|
| 1 | **Rotate all credentials exposed in `scripts` repo** — Windows passwords, Gitea token, Telegram bot token. Then purge from Git history with `git filter-branch` or `bfg-repo-cleaner` | **CRITICAL** |
| 2 | **Rotate Gitea API token** in `hermes-recovery` — it's publicly visible. Generate new token, update all consumers, purge old from history | **CRITICAL** |
| 3 | **Make `scripts` and `hermes-recovery` PRIVATE** — they contain live credentials visible to anyone | **CRITICAL** |
| 4 | **Add `.gitignore` to all 51 repos missing one** — start with the active repos first | **HIGH** |
| 5 | **Commit or stash all dirty working trees** — 13 repos have uncommitted work at risk of loss | **HIGH** |
### 🟡 Short-Term (This Month)
| # | Action | Severity |
|---|--------|----------|
| 6 | **Reorganize `itpp-infrastructure/docs/`** into nested folders (audit/, clients/, infrastructure/, monitoring/, projects/, super-search/) | **MEDIUM** |
| 7 | **Consolidate 4 MCP repos into `mcp-servers/`** as subdirectories — delete empty stubs after merge | **MEDIUM** |
| 8 | **Merge 14 single-commit business idea repos** into a `project-ideas` monorepo | **MEDIUM** |
| 9 | **Delete `auth`** (empty repo, 0 commits) | **MEDIUM** |
| 10 | **Resolve `itpp-infra` vs `itpp-infrastructure`** — archive `itpp-infra`, standardize on `itpp-infrastructure` | **MEDIUM** |
| 11 | **Add `.gitignore` entries to `hermes-skills`** for `.hub/`, `.curator_backups/` | **MEDIUM** |
| 12 | **Rename `master` → `main` on repos where it matters** (at minimum `itpp-infrastructure` to fix branch mismatch) | **LOW** |
### 🔵 Pre-Public / Pre-Open-Source
| # | Action | Severity |
|---|--------|----------|
| 13 | **Audit all 30 public repos** — ensure no private infrastructure details, client names, IPs, or credentials are exposed | **HIGH** |
| 14 | **Decide public/private policy** — which repos genuinely need to be public? Currently 71% are public. | **MEDIUM** |
| 15 | **Push 23 local-only repos to Gitea** or archive them. No code living only on a single server. | **HIGH** |
| 16 | **Clean commit history** — rebase repos with "Update YYYY-MM-DD — root" messages into meaningful commits | **LOW** |
---
## Template: Standard `.gitignore`
For any new or cleaned repo, use:
```gitignore
# OS
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
*.swp
*.swo
# Python
__pycache__/
*.py[cod]
*.egg-info/
.venv/
venv/
# Node
node_modules/
# Secrets — NEVER commit these
.env
.env.*
*.pem
*.key
credentials.json
*.token
# Cache / generated
.hub/
.curator_backups/
*.tar.gz
*.zip
# Data
*.db
*.sqlite
*.sqlite3
```
---
## Appendix: Full Repo Inventory
### Active Repos (keep as standalone)
| Repo | Commits | Last Commit | Branch | `.gitignore` | Assessment |
|------|---------|-------------|--------|-------------|------------|
| `itpp-infrastructure` | 52 | 2026-08-07 | main/master mismatch | YES | **Primary hub** — healthy |
| `hermes-skills` | 1 | 2026-07-15 | master | NO | Active mirror, 13.6MB |
| `hermes-recovery` | 1 | 2026-07-15 | master | YES | Critical backup kit |
| `scripts` | 11 | 2026-07-25 | master | NO | Active, **has secrets** |
| `homelab` | 6 | 2026-07-24 | main | NO | Active, good commits |
| `dre` | 4 | 2026-07-25 | master | NO | Active development |
| `verdicttank` | 4 | 2026-08-07 | main | NO | Active, good commits |
| `forefront-wireless-portal` | 5 | 2026-07-25 | master | NO | Active, good commits |
| `super-search-business` | 3 | 2026-07-25 | main | NO | Active |
| `voipsimplicity` | 3 | 2026-07-24 | master | NO | Active client work |
| `voipsimplicity-manual` | 1 | 2026-08-05 | master | NO | Active client work |
### Stub Repos (consolidate)
All 32 repos below are single-commit documentation stubs with no ongoing development. Consolidate into `project-ideas/` monorepo or relevant parent repo:
`apex-track`, `backup-restore`, `boxpilot`, `content-creation-pipeline`, `digital-signage`, `disaster-recovery`, `fleettracker360`, `gift-a-roast`, `hudu`, `itpropartner-website`, `launchcheck`, `mcp-browser`, `mcp-email`, `mcp-filesystem`, `mcp-git`, `mcp-servers`, `model-fallback`, `mooresunnydaze`, `nvr-shield`, `ops-portal`, `osint-tool`, `personal-assistant`, `pipeline`, `shark-game`, `startup-studio`, `super-search`, `track-a-flock`, `unifi`, `unms`, `cartmylist`
### To Delete or Archive
| Repo | Reason |
|------|--------|
| `auth` | Empty (0 commits, 0 content) |
| `itpp-infra` | Stale duplicate of `itpp-infrastructure`, SSH-only remote, 1 commit |
| `cartmylist-repo` | Local clone with SSH remote, mismatched name (real one is `cartmylist` on Gitea) |
### Local-Only (push or archive)
`assistant`, `auth`, `capabilities`, `hear-read`, `intelsight`, `intelsight-landing`, `internal`, `mockup`, `my-itpropartner-portal`, `ops`, `ops-v2-portal`, `osint`, `proposals`, `pry`, `research-search-mcp`, `schedule`, `shonuff`, `shonuff-caller`, `static`, `status`, `voice-previews`
---
*Report generated by Hermes Agent git-audit workflow. Next audit recommended: 2026-11-08.*