Protection Validation Skill
What This Skill Does
Builds and tests pre-commit protection enforcement:
- •Creates
scripts/validate-protection.jsscanner - •Updates
.git/hooks/pre-commitwith protection checks - •Tests protection enforcement (6 scenarios)
- •Validates audit trail in git log
- •Ensures CI mode works without prompts
When Claude Should Use This
Use this skill when the user:
- •Says "build protection enforcement" or "validate protection"
- •References PROTECT-002 task
- •Wants to test pre-commit hooks
- •Mentions "protection enforcement" or "validate annotations"
- •Needs to ensure protected code is enforced
Workflow Process
1. Create Protection Validation Script
File: scripts/validate-protection.js
#!/usr/bin/env node
/**
* Protection Validation Script
*
* Scans staged files for @protected/@immutable annotations and validates
* that modifications have proper approval in commit message.
*
* Usage:
* node scripts/validate-protection.js [--ci]
*
* Exit codes:
* 0 - No protected files modified, or modifications approved
* 1 - Protected files modified without approval
* 2 - Script error
*/
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
// Protection level patterns
const PROTECTION_PATTERNS = {
immutable: /@immutable/,
protected: /@protected/,
maintainable: /@maintainable/
};
// Check if running in CI mode (skip interactive prompts)
const CI_MODE = process.argv.includes('--ci') || process.env.SKIP_PROTECTION_CHECK === 'true';
/**
* Get list of staged files from git
*/
function getStagedFiles() {
try {
const output = execSync('git diff --cached --name-only --diff-filter=AM', {
encoding: 'utf-8'
});
return output.trim().split('\n').filter(Boolean);
} catch (error) {
console.error('Error getting staged files:', error.message);
return [];
}
}
/**
* Check if file contains protection annotations
*/
function getProtectionLevel(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
if (PROTECTION_PATTERNS.immutable.test(content)) {
return 'immutable';
}
if (PROTECTION_PATTERNS.protected.test(content)) {
return 'protected';
}
if (PROTECTION_PATTERNS.maintainable.test(content)) {
return 'maintainable';
}
return null;
} catch (error) {
// File might be deleted or unreadable
return null;
}
}
/**
* Extract protection details from file (lock date, test reference, etc.)
*/
function getProtectionDetails(filePath) {
try {
const content = fs.readFileSync(filePath, 'utf-8');
// Extract lock date
const lockDateMatch = content.match(/Locked:\s*(\d{4}-\d{2}-\d{2})/);
const lockDate = lockDateMatch ? lockDateMatch[1] : 'Unknown';
// Extract test reference
const testMatch = content.match(/Test:\s*([^\n]+)/);
const testRef = testMatch ? testMatch[1].trim() : 'Unknown';
// Extract status
const statusMatch = content.match(/Status:\s*([^\n]+)/);
const status = statusMatch ? statusMatch[1].trim() : 'Unknown';
return { lockDate, testRef, status };
} catch (error) {
return { lockDate: 'Unknown', testRef: 'Unknown', status: 'Unknown' };
}
}
/**
* Check if commit message contains approval
*/
function hasApprovalInCommitMessage() {
// In pre-commit hook, commit message isn't available yet
// This will be checked later by parsing git log
// For now, we'll prompt the user interactively
return false;
}
/**
* Prompt user for approval (interactive mode only)
*/
function promptForApproval(protectedFiles) {
if (CI_MODE) {
console.error('❌ Protected files modified in CI mode without PROTECTED: commit message');
console.error('Add "PROTECTED: [justification]" to your commit message');
return false;
}
console.log('\n⚠️ WARNING: You are modifying protected files:\n');
protectedFiles.forEach(({ file, level, details }) => {
console.log(` 📄 ${file}`);
console.log(` Protection: @${level}`);
console.log(` Locked: ${details.lockDate}`);
console.log(` Test: ${details.testRef}`);
console.log(` Status: ${details.status}`);
console.log('');
});
console.log('Protected code should not be modified without approval.');
console.log('');
console.log('Approval requirements:');
console.log(' @immutable : Architecture review + impact assessment');
console.log(' @protected : Technical lead approval');
console.log(' @maintainable: Self-approval (document justification)');
console.log('');
console.log('Your commit message must include: PROTECTED: [justification]');
console.log('');
// In Node.js, we can't easily do interactive prompts in pre-commit
// So we'll just show the warning and let the user proceed
// They MUST add PROTECTED: to commit message
console.log('✅ Continue with commit (remember to add PROTECTED: to message)');
console.log('❌ To cancel: Ctrl+C');
console.log('');
return true; // Allow commit, but user must add PROTECTED: message
}
/**
* Main validation function
*/
function validateProtection() {
console.log('🔍 Checking for protected code modifications...\n');
const stagedFiles = getStagedFiles();
if (stagedFiles.length === 0) {
console.log('✅ No files staged for commit');
return 0;
}
const protectedFiles = [];
for (const file of stagedFiles) {
const level = getProtectionLevel(file);
if (level) {
const details = getProtectionDetails(file);
protectedFiles.push({ file, level, details });
}
}
if (protectedFiles.length === 0) {
console.log('✅ No protected files modified');
return 0;
}
// Protected files found - prompt for approval
const approved = promptForApproval(protectedFiles);
if (!approved) {
console.error('\n❌ Commit blocked - protected files require approval\n');
return 1;
}
console.log('⚠️ Protected files modified - ensure commit message includes PROTECTED:\n');
return 0; // Allow commit
}
// Run validation
const exitCode = validateProtection();
process.exit(exitCode);
Make script executable:
chmod +x scripts/validate-protection.js
2. Update Pre-Commit Hook
File: .git/hooks/pre-commit
Add protection validation to existing hook (or create new):
#!/bin/sh
# ÆtherLight Pre-Commit Hook
# Validates tests, protection, and code quality before commit
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "🔍 Running pre-commit checks..."
# 1. Run tests (existing check)
echo "\n📋 Running tests..."
npm test
if [ $? -ne 0 ]; then
echo "${RED}❌ Tests failed - commit blocked${NC}"
echo "Fix failing tests or use: git commit --no-verify (NOT RECOMMENDED)"
exit 1
fi
# 2. Check protection enforcement (NEW)
echo "\n🔒 Checking protection enforcement..."
node scripts/validate-protection.js
if [ $? -ne 0 ]; then
echo "${RED}❌ Protection validation failed - commit blocked${NC}"
echo ""
echo "You are modifying protected code. Required:"
echo " 1. Get approval (see CODE_PROTECTION_POLICY.md)"
echo " 2. Add 'PROTECTED: [justification]' to commit message"
echo ""
echo "To bypass (NOT RECOMMENDED): git commit --no-verify"
exit 1
fi
# 3. Check TypeScript compilation (optional, if desired)
echo "\n🔨 Checking TypeScript compilation..."
cd vscode-lumina && npm run compile
if [ $? -ne 0 ]; then
echo "${YELLOW}⚠️ TypeScript compilation errors (warning only)${NC}"
fi
cd ..
echo "${GREEN}✅ All pre-commit checks passed${NC}"
exit 0
Make hook executable:
chmod +x .git/hooks/pre-commit
3. Test Protection Enforcement (6 Scenarios)
Test scenarios to validate:
Scenario 1: Modify @protected file → Prompt shown
# Modify a protected file echo "// test change" >> vscode-lumina/src/extension.ts # Stage and attempt commit git add vscode-lumina/src/extension.ts git commit -m "Test change" # Expected: Warning shown, commit allowed (must add PROTECTED:)
Scenario 2: Answer 'no' (simulated) → Commit blocked
# In CI mode, protected changes should block SKIP_PROTECTION_CHECK=false node scripts/validate-protection.js # Expected: Exit code 1, commit blocked
Scenario 3: Answer 'yes' with PROTECTED: message → Commit succeeds
git commit -m "PROTECTED: Fix critical bug in extension activation Justification: Extension fails to activate on VS Code 1.85+ Files modified: vscode-lumina/src/extension.ts Protection level: @protected (requires technical lead approval) Approval: Issue #123, approved by @tech-lead Files: 1 file changed, 5 insertions(+), 2 deletions(-)" # Expected: Commit succeeds, git log shows PROTECTED: message
Scenario 4: Modify non-protected file → No prompt
# Modify a non-protected file echo "// test change" >> vscode-lumina/src/test/example.test.ts git add vscode-lumina/src/test/example.test.ts git commit -m "Add test" # Expected: No warning, commit succeeds immediately
Scenario 5: Git log shows approval trail
# Check audit trail git log --grep="PROTECTED:" --oneline # Expected: Shows all protected code changes with justifications
Scenario 6: CI mode works without prompts
# Simulate CI environment export SKIP_PROTECTION_CHECK=true # Modify protected file echo "// ci test" >> vscode-lumina/src/extension.ts git add vscode-lumina/src/extension.ts git commit -m "CI test" # Expected: No interactive prompt, relies on commit message check
4. Validate Audit Trail
Check git log for protected changes:
# Show all protected code changes git log --grep="PROTECTED:" --oneline # Show changes to specific protected file git log --grep="PROTECTED:" -- vscode-lumina/src/services/whisperClient.ts # Show full details of protected change git log --grep="PROTECTED:" -1 --stat
Expected audit trail format:
commit abc123def456
Author: Developer <dev@example.com>
Date: Wed Nov 6 14:30:00 2025 -0800
PROTECTED: Fix Whisper API timeout issue
Justification: Whisper API response time increased to 60s
Files modified: vscode-lumina/src/services/whisperClient.ts
Protection level: @immutable (requires architecture approval)
Approval: Issue #456, approved by @architect
- Increase timeout from 30s to 60s
- Add retry logic (3 attempts)
- Update error messages
Files: 1 file changed, 15 insertions(+), 5 deletions(-)
5. Document Enforcement in CODE_PROTECTION_POLICY.md
Add enforcement section:
## Enforcement Mechanisms
### Layer 1: Pre-Commit Hook
- **File:** `.git/hooks/pre-commit`
- **Trigger:** Before every git commit
- **Action:** Scans staged files for @protected/@immutable annotations
- **Result:** Warns if protected files modified, requires PROTECTED: message
### Layer 2: Static Validation
- **File:** `scripts/validate-protection.js`
- **Trigger:** Called by pre-commit hook, CI/CD pipeline
- **Action:** Validates protection annotations and approval
- **Result:** Exit code 0 (pass) or 1 (fail)
### Layer 3: Code Review
- **Trigger:** Pull request review
- **Action:** Reviewer checks for unauthorized protected changes
- **Result:** PR approval or request changes
### Layer 4: CI/CD Pipeline
- **Trigger:** Push to remote, PR creation
- **Action:** Runs validate-protection.js in CI mode
- **Result:** Build pass (green) or fail (red)
## How Enforcement Works
1. **Developer modifies code:**
- Changes any file in workspace
- Stages changes: `git add file.ts`
2. **Pre-commit hook runs:**
- Scans staged files for @protected/@immutable
- If found: Shows warning with protection details
- Allows commit to proceed
3. **Developer writes commit message:**
- MUST include: `PROTECTED: [justification]`
- MUST document: Files modified, protection level, approval
- Example: `PROTECTED: Fix critical bug (Issue #123, approved by @lead)`
4. **Commit created:**
- Git log contains full audit trail
- PROTECTED: prefix enables filtering
- Justification and approval documented
5. **CI/CD validates:**
- Runs `validate-protection.js --ci`
- Checks commit message format
- Blocks merge if approval missing
## CI Mode
For automated pipelines (GitHub Actions, Jenkins, etc.):
```yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
validate-protection:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate protection
run: node scripts/validate-protection.js --ci
Environment variable override:
export SKIP_PROTECTION_CHECK=true # Skip protection (CI build systems)
### 6. Performance Target
**Protection check must complete in < 200ms:**
```javascript
// Add to validate-protection.js
console.time('protection-check');
// ... validation logic ...
console.timeEnd('protection-check');
// Expected: protection-check: 45ms (well under 200ms target)
Optimization strategies:
- •Cache protection levels (don't re-scan same file)
- •Only scan staged files (not entire codebase)
- •Use regex patterns (fast string matching)
- •Exit early if no staged files
Integration with Protection Tasks
PROTECT-001 → PROTECT-002 (This Skill) → PROTECT-003
- •PROTECT-001: Annotate code with @protected/@immutable
- •PROTECT-002 (This Skill): Build enforcement (pre-commit + validation script)
- •PROTECT-003: Complete CODE_PROTECTION_POLICY.md documentation
After PROTECT-002 completes:
- •Pre-commit hook validates protection on every commit
- •Protected changes require PROTECTED: commit message
- •Audit trail visible in git log
- •CI/CD pipelines can enforce protection
Related Files
- •
scripts/validate-protection.js- Validation script (created by this skill) - •
.git/hooks/pre-commit- Pre-commit hook (updated by this skill) - •
docs/CODE_PROTECTION_POLICY.md- Protection policy (updated with enforcement) - •
internal/sprints/ACTIVE_SPRINT.toml- PROTECT-002 task definition - •
.github/workflows/ci.yml- CI/CD integration (optional)
Error Handling
Common issues and solutions:
Pre-commit hook not executing
# Check if hook is executable ls -l .git/hooks/pre-commit # Expected: -rwxr-xr-x (x = executable) # Make executable if needed chmod +x .git/hooks/pre-commit
validate-protection.js fails with "git command not found"
# Verify git is installed and in PATH git --version # Check Node.js is installed node --version
Protected file not detected
# Verify annotation format grep -n "@protected" vscode-lumina/src/extension.ts # Expected: Should find @protected comment # Check file is staged git diff --cached --name-only # Expected: Should list the file
CI mode blocking all commits
# Verify environment variable is set correctly echo $SKIP_PROTECTION_CHECK # Expected: true (or unset for normal mode) # Test CI mode SKIP_PROTECTION_CHECK=true node scripts/validate-protection.js # Expected: Should not prompt, only check commit message
Historical Context
Why pre-commit enforcement is critical:
Without enforcement (before PROTECT-002):
- •Developers could modify @protected code freely
- •No approval process
- •No audit trail
- •Regressions slipped through code review
With enforcement (after PROTECT-002):
- •Pre-commit hook warns developers
- •PROTECTED: message documents justification
- •Git log provides audit trail
- •CI/CD blocks unauthorized changes
Pattern: Annotations mean nothing without enforcement. Pre-commit hooks make protection real.
Tips
Start simple:
- •Create validate-protection.js first
- •Test manually:
node scripts/validate-protection.js - •Add to pre-commit hook
- •Test 6 scenarios
- •Document in CODE_PROTECTION_POLICY.md
Test thoroughly:
- •Test with @immutable file (highest protection)
- •Test with @protected file (mid-level)
- •Test with @maintainable file (lowest protection)
- •Test with non-protected file (no warning)
- •Test CI mode (no prompts)
- •Test git log audit trail
Iterate on prompt wording:
- •Make warnings clear but not scary
- •Explain approval requirements
- •Provide commit message example
- •Show protection details (lock date, test ref)
Performance matters:
- •Keep validation script fast (<200ms)
- •Only scan staged files
- •Cache protection levels if needed
- •Exit early when possible