improve security (change RLS, and allow table sensitive access only at server side, with supabase service key)

This commit is contained in:
Yannick Le Duc
2025-08-26 14:51:15 +02:00
parent 4119875f48
commit 0093f4edba
17 changed files with 1240 additions and 285 deletions

194
scripts/test-security.js Normal file
View File

@@ -0,0 +1,194 @@
#!/usr/bin/env node
/**
* Script de test de sécurité pour Mes Budgets Participatifs
* Vérifie que les politiques RLS sont bien appliquées
*/
// Charger les variables d'environnement depuis .env.local
require('dotenv').config({ path: '.env.local' });
const { createClient } = require('@supabase/supabase-js');
// Configuration
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
if (!supabaseUrl || !supabaseAnonKey || !supabaseServiceKey) {
console.error('❌ Variables d\'environnement manquantes');
console.log('Assurez-vous d\'avoir configuré dans .env.local :');
console.log('- NEXT_PUBLIC_SUPABASE_URL');
console.log('- NEXT_PUBLIC_SUPABASE_ANON_KEY');
console.log('- SUPABASE_SERVICE_ROLE_KEY');
console.log('\n💡 Vérifiez que le fichier .env.local existe à la racine du projet');
process.exit(1);
}
const supabase = createClient(supabaseUrl, supabaseAnonKey);
const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey);
console.log('🔒 Test de sécurité - Mes Budgets Participatifs\n');
async function testSecurity() {
let allTestsPassed = true;
// Test 1: Vérifier que les tables existent
console.log('1⃣ Vérification de l\'existence des tables...');
try {
const { data: campaigns, error: campaignsError } = await supabase
.from('campaigns')
.select('id')
.limit(1);
if (campaignsError) {
console.log('❌ Table campaigns non accessible');
allTestsPassed = false;
} else {
console.log('✅ Table campaigns accessible');
}
const { data: adminUsers, error: adminUsersError } = await supabase
.from('admin_users')
.select('id')
.limit(1);
if (adminUsersError) {
console.log('❌ Table admin_users non accessible');
allTestsPassed = false;
} else {
console.log('✅ Table admin_users accessible');
}
} catch (error) {
console.log('❌ Erreur lors de la vérification des tables:', error.message);
allTestsPassed = false;
}
// Test 2: Vérifier les politiques RLS
console.log('\n2⃣ Vérification des politiques RLS...');
try {
// Test lecture publique des campagnes
const { data: publicCampaigns, error: publicCampaignsError } = await supabase
.from('campaigns')
.select('id, title')
.limit(1);
if (publicCampaignsError) {
console.log('❌ Lecture publique des campagnes bloquée');
allTestsPassed = false;
} else {
console.log('✅ Lecture publique des campagnes autorisée');
}
// Test création publique des campagnes (doit être bloquée)
const { data: createCampaign, error: createCampaignError } = await supabase
.from('campaigns')
.insert({
title: 'Test Campaign',
description: 'Test Description',
budget_per_user: 100,
spending_tiers: '10,25,50,100'
})
.select();
if (createCampaignError && createCampaignError.code === '42501') {
console.log('✅ Création de campagnes bloquée pour les utilisateurs non authentifiés');
} else if (createCampaign) {
console.log('❌ Création de campagnes autorisée pour les utilisateurs non authentifiés');
allTestsPassed = false;
} else {
console.log('⚠️ Erreur inattendue lors du test de création:', createCampaignError?.message);
}
} catch (error) {
console.log('❌ Erreur lors de la vérification des politiques RLS:', error.message);
allTestsPassed = false;
}
// Test 3: Vérifier l'accès admin avec clé de service
console.log('\n3⃣ Vérification de l\'accès administrateur...');
try {
const { data: adminCampaigns, error: adminCampaignsError } = await supabaseAdmin
.from('campaigns')
.select('id, title')
.limit(1);
if (adminCampaignsError) {
console.log('❌ Accès administrateur aux campagnes bloqué');
allTestsPassed = false;
} else {
console.log('✅ Accès administrateur aux campagnes autorisé');
}
// Test création avec clé de service
const { data: newCampaign, error: newCampaignError } = await supabaseAdmin
.from('campaigns')
.insert({
title: 'Test Admin Campaign',
description: 'Test Admin Description',
budget_per_user: 100,
spending_tiers: '10,25,50,100'
})
.select();
if (newCampaignError) {
console.log('❌ Création de campagne avec clé de service bloquée');
allTestsPassed = false;
} else {
console.log('✅ Création de campagne avec clé de service autorisée');
// Nettoyer le test
await supabaseAdmin
.from('campaigns')
.delete()
.eq('id', newCampaign[0].id);
}
} catch (error) {
console.log('❌ Erreur lors de la vérification de l\'accès admin:', error.message);
allTestsPassed = false;
}
// Test 4: Vérifier les fonctions utilitaires
console.log('\n4⃣ Vérification des fonctions utilitaires...');
try {
const { data: stats, error: statsError } = await supabase
.rpc('get_campaign_stats', { campaign_uuid: '00000000-0000-0000-0000-000000000000' });
if (statsError) {
console.log('❌ Fonction get_campaign_stats non accessible');
allTestsPassed = false;
} else {
console.log('✅ Fonction get_campaign_stats accessible');
}
} catch (error) {
console.log('❌ Erreur lors de la vérification des fonctions:', error.message);
allTestsPassed = false;
}
// Résumé
console.log('\n📊 Résumé des tests de sécurité');
console.log('================================');
if (allTestsPassed) {
console.log('🎉 Tous les tests de sécurité sont passés !');
console.log('✅ Votre application est correctement sécurisée');
console.log('✅ Les politiques RLS sont bien appliquées');
console.log('✅ L\'accès administrateur fonctionne');
console.log('✅ Les pages publiques restent accessibles');
} else {
console.log('❌ Certains tests de sécurité ont échoué');
console.log('⚠️ Vérifiez votre configuration et les politiques RLS');
console.log('📖 Consultez le guide de migration : MIGRATION-GUIDE.md');
}
return allTestsPassed;
}
// Exécuter les tests
testSecurity()
.then((success) => {
process.exit(success ? 0 : 1);
})
.catch((error) => {
console.error('❌ Erreur lors des tests:', error);
process.exit(1);
});