feat(governance): integrate Wave 5 mechanisms into session lifecycle
Enhanced session-init.js (3 new checks):
- Section 2b: Hook approval cache reset (inst_061)
Clears stale session approvals on new session
- Section 8a: Defense-in-depth health check (inst_072)
Verifies 5 credential protection layers on startup
- Section 8b: Dependency license check (inst_080)
Ensures Apache 2.0 compatibility before work begins
Enhanced session-closedown.js (2 new summaries):
- Scope adjustment summary (inst_052)
Reports scope changes made during session in handoff
- Hook approval summary (inst_061)
Documents cached "don't ask again" approvals
Architecture:
- Session-scoped mechanisms now properly integrated
- Lifecycle enforcement ensures no state leakage between sessions
- Handoff documents now include complete session activity tracking
Related: Wave 5 (fec27fd) - 100% enforcement coverage
📊 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
fec27fd54a
commit
b38eebb0c0
2 changed files with 136 additions and 0 deletions
|
|
@ -668,6 +668,64 @@ async function interactiveDeployment(gitAnalysis, autoAnswer = null) {
|
|||
return deploymentResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Get scope adjustment summary (inst_052)
|
||||
*/
|
||||
function getScopeAdjustmentSummary() {
|
||||
const scopeLogPath = path.join(__dirname, '../.claude/scope-adjustments.json');
|
||||
|
||||
if (!fs.existsSync(scopeLogPath)) {
|
||||
return '✅ No scope adjustments made this session';
|
||||
}
|
||||
|
||||
const log = JSON.parse(fs.readFileSync(scopeLogPath, 'utf8'));
|
||||
const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8'));
|
||||
const sessionAdjustments = log.adjustments.filter(a => a.sessionId === sessionState.sessionId);
|
||||
|
||||
if (sessionAdjustments.length === 0) {
|
||||
return '✅ No scope adjustments made this session';
|
||||
}
|
||||
|
||||
let summary = `⚠️ **${sessionAdjustments.length} scope adjustment(s) made:**\n\n`;
|
||||
sessionAdjustments.forEach((adj, idx) => {
|
||||
summary += `${idx + 1}. **${adj.type.toUpperCase()}** (message #${adj.messageNumber})\n`;
|
||||
summary += ` - Rationale: ${adj.rationale}\n`;
|
||||
if (adj.details) {
|
||||
summary += ` - Details: ${adj.details}\n`;
|
||||
}
|
||||
summary += ` - User discretion: ${adj.userGrantedDiscretion ? 'Yes' : 'No'}\n\n`;
|
||||
});
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: Get hook approval summary (inst_061)
|
||||
*/
|
||||
function getHookApprovalSummary() {
|
||||
const approvalCachePath = path.join(__dirname, '../.claude/approval-cache.json');
|
||||
|
||||
if (!fs.existsSync(approvalCachePath)) {
|
||||
return '✅ No hook approvals cached';
|
||||
}
|
||||
|
||||
const cache = JSON.parse(fs.readFileSync(approvalCachePath, 'utf8'));
|
||||
const sessionState = JSON.parse(fs.readFileSync(SESSION_STATE_PATH, 'utf8'));
|
||||
|
||||
if (cache.sessionId !== sessionState.sessionId || cache.approvals.length === 0) {
|
||||
return '✅ No hook approvals cached for this session';
|
||||
}
|
||||
|
||||
let summary = `📋 **${cache.approvals.length} approval(s) cached:**\n\n`;
|
||||
summary += '_These "don\'t ask again" approvals will be reset at next session start._\n\n';
|
||||
|
||||
cache.approvals.forEach((approval, idx) => {
|
||||
summary += `${idx + 1}. \`${approval.commandType}\` in \`${approval.directory}\`\n`;
|
||||
});
|
||||
|
||||
return summary + '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Phase 5: Create Handoff Document (AT END with all results)
|
||||
*/
|
||||
|
|
@ -801,6 +859,18 @@ ${gitAnalysis.recent_commits.join('\n')}
|
|||
|
||||
---
|
||||
|
||||
## Session Activity Tracking
|
||||
|
||||
### Scope Adjustments (inst_052)
|
||||
|
||||
${getScopeAdjustmentSummary()}
|
||||
|
||||
### Hook Approvals (inst_061)
|
||||
|
||||
${getHookApprovalSummary()}
|
||||
|
||||
---
|
||||
|
||||
## Next Session
|
||||
|
||||
**Startup Sequence**:
|
||||
|
|
|
|||
|
|
@ -371,6 +371,30 @@ async function main() {
|
|||
log(` Could not check background processes: ${err.message}`, 'yellow');
|
||||
}
|
||||
|
||||
// Hook approval cache reset (inst_061)
|
||||
section('2b. Hook Approval Cache Reset (inst_061)');
|
||||
try {
|
||||
const approvalCache = '.claude/approval-cache.json';
|
||||
if (fs.existsSync(approvalCache)) {
|
||||
const cache = JSON.parse(fs.readFileSync(approvalCache, 'utf8'));
|
||||
const state = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8'));
|
||||
|
||||
if (cache.sessionId !== state.sessionId) {
|
||||
// Session changed - reset cache
|
||||
cache.sessionId = state.sessionId;
|
||||
cache.approvals = [];
|
||||
fs.writeFileSync(approvalCache, JSON.stringify(cache, null, 2));
|
||||
success('Hook approval cache reset for new session');
|
||||
} else {
|
||||
log(` ${cache.approvals.length} approval(s) cached from current session`, 'cyan');
|
||||
}
|
||||
} else {
|
||||
success('No approval cache (will be created on first use)');
|
||||
}
|
||||
} catch (err) {
|
||||
log(` Could not check approval cache: ${err.message}`, 'yellow');
|
||||
}
|
||||
|
||||
// Load instruction history
|
||||
section('3. Loading Instruction History');
|
||||
const instructions = loadInstructionHistory();
|
||||
|
|
@ -685,6 +709,48 @@ async function main() {
|
|||
warning(`Could not run CSP scan: ${err.message}`);
|
||||
}
|
||||
|
||||
// Defense-in-Depth Health Check (inst_072)
|
||||
section('8a. Defense-in-Depth Health Check (inst_072)');
|
||||
try {
|
||||
const auditResult = execSync('node scripts/audit-defense-in-depth.js 2>&1', {
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe'
|
||||
});
|
||||
|
||||
if (auditResult.includes('All 5 layers')) {
|
||||
success('All 5 credential protection layers verified');
|
||||
} else {
|
||||
const incompleteCount = (auditResult.match(/❌/g) || []).length;
|
||||
warning(`${incompleteCount} defense layer(s) incomplete`);
|
||||
log(' Run: node scripts/audit-defense-in-depth.js for details', 'cyan');
|
||||
}
|
||||
} catch (err) {
|
||||
// Non-blocking - just warn
|
||||
warning('Defense-in-depth audit incomplete (see details above)');
|
||||
}
|
||||
|
||||
// Dependency License Check (inst_080)
|
||||
section('8b. Dependency License Check (inst_080)');
|
||||
try {
|
||||
execSync('node scripts/check-dependency-licenses.js', {
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe'
|
||||
});
|
||||
success('All dependencies are Apache 2.0 compatible');
|
||||
} catch (err) {
|
||||
// Check if it's a critical failure or just warnings
|
||||
const output = err.stdout || '';
|
||||
if (output.includes('CRITICAL')) {
|
||||
error('Prohibited dependency licenses detected');
|
||||
log(' Run: node scripts/check-dependency-licenses.js for details', 'red');
|
||||
} else if (output.includes('HIGH')) {
|
||||
warning('Restrictive licenses detected (may require review)');
|
||||
log(' Run: node scripts/check-dependency-licenses.js for details', 'yellow');
|
||||
} else {
|
||||
success('Dependency licenses checked (some flagged for review)');
|
||||
}
|
||||
}
|
||||
|
||||
// ENFORCEMENT: Local development server check
|
||||
section('9. Development Environment Enforcement');
|
||||
const localServerRunning = checkLocalServer();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue