Initial commit
This commit is contained in:
272
skills/claude-md-auditor/reference/ci-cd-integration.md
Normal file
272
skills/claude-md-auditor/reference/ci-cd-integration.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# CI/CD Integration Examples
|
||||
|
||||
Ready-to-use configurations for automated CLAUDE.md validation.
|
||||
|
||||
## Pre-Commit Hook
|
||||
|
||||
### Basic Validation
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# .git/hooks/pre-commit
|
||||
|
||||
if git diff --cached --name-only | grep -q "CLAUDE.md"; then
|
||||
echo "Validating CLAUDE.md..."
|
||||
|
||||
FILE=$(git diff --cached --name-only | grep "CLAUDE.md" | head -1)
|
||||
|
||||
# Check file length
|
||||
LINES=$(wc -l < "$FILE")
|
||||
if [ "$LINES" -gt 500 ]; then
|
||||
echo "ERROR: CLAUDE.md is $LINES lines (max 500)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for secrets
|
||||
if grep -qE "password|secret|token|api_key|-----BEGIN" "$FILE"; then
|
||||
echo "ERROR: Potential secrets detected in CLAUDE.md"
|
||||
echo "Run: grep -nE 'password|secret|token|api_key' $FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for broken imports
|
||||
grep "^@" "$FILE" | while read -r import; do
|
||||
path="${import#@}"
|
||||
if [ ! -f "$path" ]; then
|
||||
echo "ERROR: Broken import: $import"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "CLAUDE.md validation passed"
|
||||
fi
|
||||
```
|
||||
|
||||
### Installation
|
||||
```bash
|
||||
chmod +x .git/hooks/pre-commit
|
||||
```
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
### Basic Workflow
|
||||
|
||||
```yaml
|
||||
# .github/workflows/claude-md-audit.yml
|
||||
name: CLAUDE.md Audit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '**/CLAUDE.md'
|
||||
- '**/.claude/CLAUDE.md'
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Find CLAUDE.md files
|
||||
id: find
|
||||
run: |
|
||||
files=$(find . -name "CLAUDE.md" -type f)
|
||||
echo "files=$files" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check file lengths
|
||||
run: |
|
||||
for file in ${{ steps.find.outputs.files }}; do
|
||||
lines=$(wc -l < "$file")
|
||||
if [ "$lines" -gt 500 ]; then
|
||||
echo "::error file=$file::File is $lines lines (max 500)"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: $file ($lines lines)"
|
||||
done
|
||||
|
||||
- name: Check for secrets
|
||||
run: |
|
||||
for file in ${{ steps.find.outputs.files }}; do
|
||||
if grep -qE "password|secret|token|api_key|-----BEGIN" "$file"; then
|
||||
echo "::error file=$file::Potential secrets detected"
|
||||
grep -nE "password|secret|token|api_key" "$file" || true
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "No secrets detected"
|
||||
|
||||
- name: Check imports
|
||||
run: |
|
||||
for file in ${{ steps.find.outputs.files }}; do
|
||||
dir=$(dirname "$file")
|
||||
grep "^@" "$file" | while read -r import; do
|
||||
path="${import#@}"
|
||||
if [ ! -f "$dir/$path" ]; then
|
||||
echo "::error file=$file::Broken import: $import"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
echo "All imports valid"
|
||||
```
|
||||
|
||||
### With PR Comment
|
||||
|
||||
```yaml
|
||||
- name: Post audit summary
|
||||
if: always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
|
||||
// Collect results
|
||||
const results = {
|
||||
files: 0,
|
||||
passed: 0,
|
||||
failed: 0,
|
||||
warnings: []
|
||||
};
|
||||
|
||||
// Post comment
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: context.issue.number,
|
||||
body: `## CLAUDE.md Audit Results
|
||||
|
||||
- Files checked: ${results.files}
|
||||
- Passed: ${results.passed}
|
||||
- Failed: ${results.failed}
|
||||
|
||||
${results.warnings.length > 0 ? '### Warnings\n' + results.warnings.join('\n') : ''}
|
||||
`
|
||||
});
|
||||
```
|
||||
|
||||
## VS Code Task
|
||||
|
||||
### tasks.json
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Audit CLAUDE.md",
|
||||
"type": "shell",
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"-c",
|
||||
"echo 'Auditing CLAUDE.md...' && wc -l CLAUDE.md && grep -c '^##' CLAUDE.md && echo 'Done'"
|
||||
],
|
||||
"group": "test",
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "new"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Check CLAUDE.md secrets",
|
||||
"type": "shell",
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"-c",
|
||||
"if grep -qE 'password|secret|token|api_key' CLAUDE.md; then echo 'WARNING: Potential secrets found:' && grep -nE 'password|secret|token|api_key' CLAUDE.md; else echo 'No secrets detected'; fi"
|
||||
],
|
||||
"group": "test",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Keyboard Shortcut
|
||||
|
||||
```json
|
||||
// keybindings.json
|
||||
{
|
||||
"key": "ctrl+shift+a",
|
||||
"command": "workbench.action.tasks.runTask",
|
||||
"args": "Audit CLAUDE.md"
|
||||
}
|
||||
```
|
||||
|
||||
## Husky + lint-staged
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
npm install -D husky lint-staged
|
||||
npx husky init
|
||||
```
|
||||
|
||||
### package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"lint-staged": {
|
||||
"**/CLAUDE.md": [
|
||||
"bash -c 'wc -l \"$0\" | awk \"{if (\\$1 > 500) {print \\\"ERROR: \\\" \\$1 \\\" lines\\\"; exit 1}}\"'",
|
||||
"bash -c 'grep -qE \"password|secret|token\" \"$0\" && exit 1 || true'"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### .husky/pre-commit
|
||||
|
||||
```bash
|
||||
npx lint-staged
|
||||
```
|
||||
|
||||
## GitLab CI
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
claude-md-audit:
|
||||
stage: test
|
||||
rules:
|
||||
- changes:
|
||||
- "**/CLAUDE.md"
|
||||
script:
|
||||
- |
|
||||
for file in $(find . -name "CLAUDE.md"); do
|
||||
echo "Checking $file"
|
||||
lines=$(wc -l < "$file")
|
||||
if [ "$lines" -gt 500 ]; then
|
||||
echo "ERROR: $file is $lines lines"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
- echo "CLAUDE.md audit passed"
|
||||
```
|
||||
|
||||
## Makefile Target
|
||||
|
||||
```makefile
|
||||
.PHONY: audit-claude-md
|
||||
|
||||
audit-claude-md:
|
||||
@echo "Auditing CLAUDE.md files..."
|
||||
@find . -name "CLAUDE.md" -exec sh -c '\
|
||||
lines=$$(wc -l < "{}"); \
|
||||
if [ "$$lines" -gt 500 ]; then \
|
||||
echo "ERROR: {} is $$lines lines"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo "OK: {} ($$lines lines)"' \;
|
||||
@echo "Checking for secrets..."
|
||||
@! grep -rE "password|secret|token|api_key" --include="CLAUDE.md" . || \
|
||||
(echo "ERROR: Secrets detected" && exit 1)
|
||||
@echo "Audit complete"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Fail fast**: Check secrets before anything else
|
||||
2. **Clear errors**: Include file path and line numbers
|
||||
3. **PR feedback**: Post results as comments
|
||||
4. **Gradual adoption**: Start with warnings, then enforce
|
||||
5. **Skip when needed**: Allow `[skip audit]` in commit message
|
||||
Reference in New Issue
Block a user