fix: add visibility check to getDocument/getTranslations endpoints
Non-public documents (internal, archived, confidential) were accessible to unauthenticated users via direct slug/ID lookup. List and search endpoints already filtered for visibility: 'public', but the individual document endpoints did not. Added optionalAuth middleware and visibility checks so non-public docs return 404 to public users while remaining accessible to admin users. Also adds Guardian Agents translations to village-case-study locale files (DE, FR, MI) — 8 new keys per locale, flow step renumbered 6→7→8 with new Guardian Agents verification step at position 6. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8b1527c5d8
commit
00d89ce095
5 changed files with 85 additions and 18 deletions
|
|
@ -22,7 +22,7 @@
|
|||
"ai_label": "AI-Modell:",
|
||||
"ai_value": "Souveränes Lama (QLoRA feinabgestimmt)",
|
||||
"features_label": "AI-Merkmale:",
|
||||
"features_value": "4 geregelte Funktionen live",
|
||||
"features_value": "5 geregelte Funktionen live",
|
||||
"infra_label": "Infrastruktur:",
|
||||
"infra_value": "NZ + EU (keine US-Abhängigkeit)"
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
},
|
||||
"flow": {
|
||||
"heading": "Wie Governance in der Praxis funktioniert",
|
||||
"intro": "Wenn ein Mitglied eine KI-Funktion nutzt, durchläuft die Anfrage sechs Governance-Prüfungen, bevor eine Antwort erzeugt wird. Jede Prüfung ist unabhängig und kann die Anfrage blockieren oder ändern.",
|
||||
"intro": "Wenn ein Mitglied eine KI-Funktion nutzt, durchläuft die Anfrage sieben Governance-Prüfungen, bevor eine Antwort erzeugt wird. Jede Prüfung ist unabhängig und kann die Anfrage blockieren oder ändern.",
|
||||
"steps": {
|
||||
"1": {
|
||||
"title": "Antrag eines Mitglieds erhalten",
|
||||
|
|
@ -76,12 +76,16 @@
|
|||
"desc": "Das souveräne Llama-Modell erzeugt eine Antwort unter Verwendung des RAG-Kontextes, gefiltert nach den Berechtigungen des Mitglieds. Die gesamte Verarbeitung bleibt in der Infrastruktur."
|
||||
},
|
||||
"6": {
|
||||
"title": "Guardian Agents Verifizierung",
|
||||
"desc": "Jede Tatsachenbehauptung in der Antwort wird anhand des Quellmaterials mittels Kosinusähnlichkeit von Embeddings überprüft — eine mathematische Messung, kein generatives Prüfen. Jede Behauptung erhält ein Vertrauensabzeichen, das für das Mitglied sichtbar ist."
|
||||
},
|
||||
"7": {
|
||||
"title": "Überprüfung des Umfangs",
|
||||
"desc": "Entspricht die Antwort dem, was angefordert wurde? Erkennt die Ausweitung des Umfangs und blockiert Antworten, die über die ursprüngliche Anfrage hinausgehen."
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"title": "Lieferung mit Namensnennung",
|
||||
"desc": "Die Antwort wird dem Mitglied mit Quellenangabe zugestellt. Jeder Schritt wird für die Prüfung protokolliert."
|
||||
"desc": "Antwort an das Mitglied mit Vertrauensabzeichen, Quellenangabe und transparenter Argumentation. Jeder Schritt wird protokolliert."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -106,6 +110,13 @@
|
|||
"title": "AI-Speicher-Transparenz",
|
||||
"benefit": "Mitglieder können sehen, bearbeiten und löschen, was sich die KI über sie \"merkt\". Das vollständige Audit-Dashboard zeigt jede KI-Interaktion an.",
|
||||
"governance": "Steuerung: Zustimmung mehrerer Interessengruppen erforderlich. Persistenzentscheidungen werden klassifiziert und sind überprüfbar. Die Mitglieder kontrollieren ihre eigenen Daten."
|
||||
},
|
||||
"guardian": {
|
||||
"title": "Guardian Agents",
|
||||
"badge": "NEW",
|
||||
"benefit": "Jede KI-Antwort wird anhand des Quellmaterials mittels Kosinusähnlichkeit von Embeddings überprüft — eine mathematische Messung, kein generatives Modell, das das erste überprüft. Jede Tatsachenbehauptung erhält ein Vertrauensabzeichen (hoch, mittel, niedrig, unbestätigt), das für das Mitglied sichtbar ist.",
|
||||
"governance": "Steuerung: Die Verifizierung erfolgt in einem grundlegend anderen epistemischen Bereich als die Generierung — und vermeidet so Fehler gemeinsamer Ursache. Korrekturen von Moderatoren fließen in die Verifizierungsschwellen ein. Alles mandantenbezogen.",
|
||||
"link": "Philosophische Grundlagen →"
|
||||
}
|
||||
},
|
||||
"limitations": {
|
||||
|
|
@ -143,7 +154,8 @@
|
|||
"• Eine polyzentrische Verwaltung kann in der Produktion ohne übermäßigen Aufwand betrieben werden",
|
||||
"• Mandantenübergreifende Isolierung mit gemeinschaftsbezogener Governance ist möglich",
|
||||
"• Governance-Verstöße sind aufdeckbar und überprüfbar",
|
||||
"• Der Rahmen lernt aus Fehlern (dokumentierte Reaktionen auf Vorfälle)"
|
||||
"• Der Rahmen lernt aus Fehlern (dokumentierte Reaktionen auf Vorfälle)",
|
||||
"• Verifizierung ohne Fehler gemeinsamer Ursache ist erreichbar durch mathematische Ähnlichkeit statt generativer Überprüfung"
|
||||
]
|
||||
},
|
||||
"does_not_support": {
|
||||
|
|
@ -162,6 +174,7 @@
|
|||
"visit_village": "Besuchen Sie das Dorf →",
|
||||
"village_ai": "Souveränes Sprachmodell →",
|
||||
"research_paper": "Forschungspapier →",
|
||||
"guardian_paper": "Philosophie der Guardian Agents →",
|
||||
"research_details": "Forschung → Details"
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"ai_label": "Modèle AI :",
|
||||
"ai_value": "Lama souverain (QLoRA affiné)",
|
||||
"features_label": "Caractéristiques de l'IA :",
|
||||
"features_value": "4 fonctions gouvernées en direct",
|
||||
"features_value": "5 fonctions gouvernées en direct",
|
||||
"infra_label": "L'infrastructure :",
|
||||
"infra_value": "NZ + UE (pas de dépendance à l'égard des États-Unis)"
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
},
|
||||
"flow": {
|
||||
"heading": "Comment fonctionne la gouvernance dans la pratique",
|
||||
"intro": "Lorsqu'un membre utilise une fonction d'IA, la demande passe par six contrôles de gouvernance avant qu'une réponse ne soit générée. Chaque contrôle est indépendant et peut bloquer ou modifier la demande.",
|
||||
"intro": "Lorsqu'un membre utilise une fonction d'IA, la demande passe par sept contrôles de gouvernance avant qu'une réponse ne soit générée. Chaque contrôle est indépendant et peut bloquer ou modifier la demande.",
|
||||
"steps": {
|
||||
"1": {
|
||||
"title": "Demande d'adhésion reçue",
|
||||
|
|
@ -76,12 +76,16 @@
|
|||
"desc": "Le modèle du lama souverain génère une réponse en utilisant le contexte RAG filtré par les autorisations du membre. Tout le traitement reste sur l'infrastructure."
|
||||
},
|
||||
"6": {
|
||||
"title": "Vérification par les Guardian Agents",
|
||||
"desc": "Chaque affirmation factuelle dans la réponse est vérifiée par rapport au matériel source à l'aide de la similarité cosinus des embeddings — une mesure mathématique, pas une vérification générative. Chaque affirmation reçoit un badge de confiance visible par le membre."
|
||||
},
|
||||
"7": {
|
||||
"title": "Vérification du champ d'application",
|
||||
"desc": "La réponse est-elle adaptée à ce qui a été demandé ? Détecte l'élargissement du champ d'application et bloque les réponses qui dépassent la demande initiale."
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"title": "Livraison avec attribution",
|
||||
"desc": "La réponse est envoyée au membre avec l'indication de la source. Chaque étape est enregistrée à des fins d'audit."
|
||||
"desc": "Réponse fournie au membre avec des badges de confiance, l'attribution de la source et un raisonnement transparent. Chaque étape est enregistrée."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -106,6 +110,13 @@
|
|||
"title": "Transparence de la mémoire de l'IA",
|
||||
"benefit": "Les membres peuvent voir, modifier et supprimer ce que l'IA \"retient\" d'eux. Un tableau de bord d'audit complet montre chaque interaction de l'IA.",
|
||||
"governance": "Gouvernance : Le consentement de plusieurs parties prenantes est requis. Les décisions relatives à la persistance sont classifiées et vérifiables. Les membres contrôlent leurs propres données."
|
||||
},
|
||||
"guardian": {
|
||||
"title": "Guardian Agents",
|
||||
"badge": "NEW",
|
||||
"benefit": "Chaque réponse de l'IA est vérifiée par rapport au matériel source à l'aide de la similarité cosinus des embeddings — une comparaison mathématique, pas un modèle génératif qui se vérifie lui-même. Chaque affirmation factuelle reçoit un badge de confiance (élevé, moyen, faible, non vérifié) visible par le membre.",
|
||||
"governance": "Gouvernance : La vérification opère dans un domaine épistémique fondamentalement différent de celui de la génération — évitant ainsi les défaillances de mode commun. Les corrections des modérateurs alimentent les seuils de vérification. Le tout est limité au locataire.",
|
||||
"link": "Fondements philosophiques →"
|
||||
}
|
||||
},
|
||||
"limitations": {
|
||||
|
|
@ -143,7 +154,8 @@
|
|||
"• La gouvernance polycentrique peut fonctionner en production sans frais généraux prohibitifs",
|
||||
"• Il est possible d'isoler plusieurs locataires avec une gouvernance par communauté",
|
||||
"• Les violations de la gouvernance sont détectables et peuvent faire l'objet d'un audit",
|
||||
"• Le cadre tire les leçons des échecs (réponses documentées aux incidents)"
|
||||
"• Le cadre tire les leçons des échecs (réponses documentées aux incidents)",
|
||||
"• La vérification sans défaillance de mode commun est réalisable grâce à la similarité mathématique plutôt qu'à la vérification générative"
|
||||
]
|
||||
},
|
||||
"does_not_support": {
|
||||
|
|
@ -162,6 +174,7 @@
|
|||
"visit_village": "Visiter le village →",
|
||||
"village_ai": "Modèle de langue souveraine →",
|
||||
"research_paper": "Document de recherche →",
|
||||
"guardian_paper": "Philosophie des Guardian Agents →",
|
||||
"research_details": "Détails de la recherche →"
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
"ai_label": "Mōdēra AI:",
|
||||
"ai_value": "Sovereign Llama (i whakangāwarihia mō QLoRA)",
|
||||
"features_label": "Ngā āhuatanga AI:",
|
||||
"features_value": "4 āhuatanga whakahaere ora",
|
||||
"features_value": "5 āhuatanga whakahaere ora",
|
||||
"infra_label": "Tūāpapa:",
|
||||
"infra_value": "Aotearoa + Uniana o Europi (kāore he whakawhirinaki ki te US)"
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
},
|
||||
"flow": {
|
||||
"heading": "Te āhua o te whakahaere i roto i te mahi",
|
||||
"intro": "Ka whakamahi tētahi mema i tētahi āhuatanga AI, ka puta te tono i ngā tirohanga whakahaere e ono i mua i te whakaputa i tētahi whakautu. He motuhake ia tirohanga, ā, ka taea e ia te aukati, te whakarerekē rānei i te tono.",
|
||||
"intro": "Ka whakamahi tētahi mema i tētahi āhuatanga AI, ka puta te tono i ngā tirohanga whakahaere e whitu i mua i te whakaputa i tētahi whakautu. He motuhake ia tirohanga, ā, ka taea e ia te aukati, te whakarerekē rānei i te tono.",
|
||||
"steps": {
|
||||
"1": {
|
||||
"title": "Kua whiwhi i te tono a te mema",
|
||||
|
|
@ -76,12 +76,16 @@
|
|||
"desc": "Ka whakaputa urupare te tauira Llama rangatira mā te whakamahi i te horopaki RAG kua tātarihia e ngā whakaaetanga a te mema. Ka noho katoa ngā tukanga ki runga i te hanganga."
|
||||
},
|
||||
"6": {
|
||||
"title": "Te whakamana a ngā Guardian Agents",
|
||||
"desc": "Ka tirohia ia kōrero tūturu i roto i te whakautu ki ngā rauemi taketake mā te whakamahi i te ōritetanga cosine o ngā embedding — he inenga pāngarau, ehara i te tirotiro whakaputa. Ka whiwhi ia kōrero i tētahi tohu whakawhirinaki ka kitea e te mema."
|
||||
},
|
||||
"7": {
|
||||
"title": "Whakamana i te whānuitanga",
|
||||
"desc": "He tika te whakautu ki tā i pātaihia? Ka kitea te whakawhānuitanga o te kaupapa, ā, ka aukati i ngā whakautu e neke atu ana i te tono taketake."
|
||||
},
|
||||
"7": {
|
||||
"8": {
|
||||
"title": "Tuku me te tohu kaituhi",
|
||||
"desc": "Ka tukuna te whakautu ki te mema me te tohu i te puna. Ka tuhia ia hikoinga mō te arotake."
|
||||
"desc": "Whakautu i tukuna ki te mema me ngā tohu whakawhirinaki, te tohu pūtake, me te whakamārama mārama. Ka tuhia ia hikoinga."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -106,6 +110,13 @@
|
|||
"title": "Mārama o te Mahara AI",
|
||||
"benefit": "Ka taea e ngā mema te kite, te whakatika, me te muku i ngā mea e 'maumahara ana' te AI mō rātou. Ka whakaatu te papamātātai arotake katoa i ia whakawhitinga katoa ki te AI.",
|
||||
"governance": "Whakahaere: Me whakaae ngā kaiwhai pānga maha. Ka whakarōpūhia ngā whakataunga mō te manawanui, ā, ka taea te arotake. Ka whakahaere ngā mema i ā rātou ake raraunga."
|
||||
},
|
||||
"guardian": {
|
||||
"title": "Guardian Agents",
|
||||
"badge": "NEW",
|
||||
"benefit": "Ka whakamana ia whakautu AI ki ngā rauemi taketake mā te whakamahi i te ōritetanga cosine o ngā embedding — he whakataurite pāngarau, ehara i te tauira whakaputa e tirotiro ana i a ia anō. Ka whiwhi ia kōrero tūturu i tētahi tohu whakawhirinaki (teitei, waenga, iti, kāore i te whakamana) ka kitea e te mema.",
|
||||
"governance": "Whakahaere: He rāngai mātauranga tino rerekē tō te whakamana i te rāngai whakaputa — ā, mā reira e karo ai ngā tauira hapa aronga-kotahi. Ka whāngai ngā whakatikanga a ngā kaiwhakahaere ki ngā paenga whakamana. Katoa he ā-teneti.",
|
||||
"link": "Ngā tūāpapa arorangi →"
|
||||
}
|
||||
},
|
||||
"limitations": {
|
||||
|
|
@ -143,7 +154,8 @@
|
|||
"• Ka taea e te whakahaere ā-pokapū maha te whakahaere i roto i te whakaputanga me te kore he utu taumata teitei",
|
||||
"• Ka taea te wehewehe maha-teneti me te whakahaere ā-hapori",
|
||||
"• Ka taea te kitea, ka taea hoki te arotake i ngā hē whakahaere",
|
||||
"• Ka ako te anga i ngā hapa (ngā urupare aitua kua tuhia)"
|
||||
"• Ka ako te anga i ngā hapa (ngā urupare aitua kua tuhia)",
|
||||
"• Ka taea te whakamana me te kore hapa aronga-kotahi mā te whakamahi i te ōritetanga pāngarau, kaua ko te tirotiro whakaputa"
|
||||
]
|
||||
},
|
||||
"does_not_support": {
|
||||
|
|
@ -162,6 +174,7 @@
|
|||
"visit_village": "Haere ki te kāinga →",
|
||||
"village_ai": "Mōdela Reo Rangatira →",
|
||||
"research_paper": "Pepa Rangahau →",
|
||||
"guardian_paper": "Te Aronga Hinengaro o ngā Guardian Agents →",
|
||||
"research_details": "Ngā taipitopito rangahau →"
|
||||
}
|
||||
}
|
||||
|
|
@ -103,6 +103,15 @@ async function getDocument(req, res) {
|
|||
});
|
||||
}
|
||||
|
||||
// SECURITY: Non-public documents only accessible to admin users
|
||||
const isAdmin = req.user && req.user.role === 'admin';
|
||||
if (document.visibility !== 'public' && !isAdmin) {
|
||||
return res.status(404).json({
|
||||
error: 'Not Found',
|
||||
message: 'Document not found'
|
||||
});
|
||||
}
|
||||
|
||||
// If language parameter provided and not English, return translated version
|
||||
if (lang && lang !== 'en') {
|
||||
const supportedLangs = ['de', 'fr'];
|
||||
|
|
@ -146,6 +155,14 @@ async function getDocument(req, res) {
|
|||
const translatedDoc = await Document.findBySlug(translatedSlug);
|
||||
|
||||
if (translatedDoc) {
|
||||
// SECURITY: Visibility check on fallback document too
|
||||
if (translatedDoc.visibility !== 'public' && !isAdmin) {
|
||||
return res.status(404).json({
|
||||
error: 'Not Found',
|
||||
message: 'Document not found'
|
||||
});
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
document: {
|
||||
|
|
@ -652,6 +669,15 @@ async function getTranslations(req, res) {
|
|||
});
|
||||
}
|
||||
|
||||
// SECURITY: Non-public documents only accessible to admin users
|
||||
const isAdmin = req.user && req.user.role === 'admin';
|
||||
if (document.visibility !== 'public' && !isAdmin) {
|
||||
return res.status(404).json({
|
||||
error: 'Not Found',
|
||||
message: 'Document not found'
|
||||
});
|
||||
}
|
||||
|
||||
// Build list of available translations
|
||||
const translations = {
|
||||
en: {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const express = require('express');
|
|||
const router = express.Router();
|
||||
|
||||
const documentsController = require('../controllers/documents.controller');
|
||||
const { authenticateToken, requireRole } = require('../middleware/auth.middleware');
|
||||
const { authenticateToken, requireRole, optionalAuth } = require('../middleware/auth.middleware');
|
||||
const { validateRequired, validateObjectId, validateSlug } = require('../middleware/validation.middleware');
|
||||
const { asyncHandler } = require('../middleware/error.middleware');
|
||||
|
||||
|
|
@ -47,13 +47,15 @@ router.get('/', (req, res, next) => {
|
|||
next();
|
||||
}, asyncHandler(documentsController.listDocuments));
|
||||
|
||||
// GET /api/documents/:identifier/translations (public)
|
||||
// GET /api/documents/:identifier/translations (public, visibility-filtered)
|
||||
router.get('/:identifier/translations',
|
||||
optionalAuth,
|
||||
asyncHandler(documentsController.getTranslations)
|
||||
);
|
||||
|
||||
// GET /api/documents/:identifier (ID or slug)
|
||||
// GET /api/documents/:identifier (ID or slug, visibility-filtered)
|
||||
router.get('/:identifier',
|
||||
optionalAuth,
|
||||
asyncHandler(documentsController.getDocument)
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue