Transitioning from Report-Only to Enforcement
Transitioning from Report-Only to Enforcement
The transition from Report-Only to enforcement mode requires careful planning and gradual implementation:
// CSP Migration Manager
class CSPMigrationManager {
constructor(config) {
this.config = config;
this.stages = [
'initial-report-only',
'refined-report-only',
'partial-enforcement',
'full-enforcement'
];
this.currentStage = 0;
}
async evaluateReadiness() {
const metrics = await this.gatherMetrics();
const readiness = {
violationRate: this.evaluateViolationRate(metrics),
policyStability: this.evaluatePolicyStability(metrics),
criticalPaths: this.evaluateCriticalPaths(metrics),
userImpact: this.evaluateUserImpact(metrics)
};
const overallScore = this.calculateReadinessScore(readiness);
return {
ready: overallScore >= this.config.readinessThreshold,
score: overallScore,
details: readiness,
recommendations: this.generateMigrationRecommendations(readiness)
};
}
async migrateToNextStage() {
const readiness = await this.evaluateReadiness();
if (!readiness.ready) {
throw new Error(`Not ready for migration: ${JSON.stringify(readiness.details)}`);
}
this.currentStage++;
const nextStage = this.stages[this.currentStage];
switch (nextStage) {
case 'refined-report-only':
return this.applyRefinedReportOnly();
case 'partial-enforcement':
return this.applyPartialEnforcement();
case 'full-enforcement':
return this.applyFullEnforcement();
default:
throw new Error(`Unknown stage: ${nextStage}`);
}
}
applyRefinedReportOnly() {
// Apply refined policy based on violation analysis
return {
headers: {
'Content-Security-Policy-Report-Only': this.buildRefinedPolicy()
},
monitoring: {
duration: '2 weeks',
successCriteria: {
maxViolationRate: 0.1, // per 1000 page views
criticalPathViolations: 0
}
}
};
}
applyPartialEnforcement() {
// Enforce for logged-out users, report-only for logged-in
return {
middleware: (req, res, next) => {
const policy = this.buildRefinedPolicy();
if (req.user) {
// Logged-in users get report-only
res.setHeader('Content-Security-Policy-Report-Only', policy);
} else {
// Logged-out users get enforcement
res.setHeader('Content-Security-Policy', policy);
}
next();
},
monitoring: {
duration: '1 week',
rollbackTriggers: {
errorRateIncrease: 0.05,
supportTicketIncrease: 0.1
}
}
};
}
applyFullEnforcement() {
// Full enforcement with gradual rollout
return {
rolloutStrategy: 'percentage',
stages: [
{ percentage: 1, duration: '1 day' },
{ percentage: 5, duration: '2 days' },
{ percentage: 25, duration: '3 days' },
{ percentage: 50, duration: '3 days' },
{ percentage: 100, duration: 'permanent' }
],
middleware: (req, res, next) => {
const rolloutPercentage = this.getCurrentRolloutPercentage();
const userHash = this.hashUser(req);
if (userHash % 100 < rolloutPercentage) {
res.setHeader('Content-Security-Policy', this.buildRefinedPolicy());
} else {
res.setHeader('Content-Security-Policy-Report-Only', this.buildRefinedPolicy());
}
next();
}
};
}
}