v3 : points de la relecture indépendante — une personne une voix, ordre de déploiement, durcissements
- Dans Monnaie libre (électorat = toile de confiance), seuls les membres de la toile votent (trustin_access::votes_in) ; une identité d'invitation y lit, propose et signale. L'interface le dit à la place des boutons (fr/en/es). - Un lien d'invitation ne vise jamais une identité Ğ1 ; le lien est réservé avant de créer l'identité (deux acceptations simultanées : une seule passe). - Un nombre n'est jamais une coquille (« 50 » → « 5,0 », « 1 5 » → « 15 »). - Redirection après connexion : caractères de contrôle refusés. - En-têtes : X-Frame-Options DENY, frame-ancestors 'none', nosniff, Referrer-Policy. - Déploiement : le produit passe en premier ; la maquette attend son succès. Les conteneurs, même arrêtés, qui revendiquent encore la racine sortent de « restart: always » (ils reviendraient au redémarrage de Docker). - Tests : 57 Rust (dont 14 scénarios d'API), e2e 12 / 12 avec C11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -133,3 +133,25 @@ test('C10 — trustinWallet : la gestion des accès est réservée', async ({ br
|
||||
await yvv.getByRole('button', { name: "Créer le lien d'invitation" }).click();
|
||||
await expect(yvv.locator('.link code')).toContainText('/invitation#');
|
||||
});
|
||||
|
||||
test('C11 — une personne, une voix : dans Monnaie libre, seuls les membres de la toile votent', async ({ browser }) => {
|
||||
const yvv = await person(browser, 'Yvv', true);
|
||||
const r = await yvv.request.post('/api/access/invitations', {
|
||||
data: { label: 'Invitée', groups: ['monnaie-libre', 'essai'] },
|
||||
headers: { 'x-requested-with': 'libredecision' },
|
||||
});
|
||||
const { link } = (await r.json()) as { link: string };
|
||||
const ctx = await browser.newContext({ locale: 'fr-FR' });
|
||||
const invited = await ctx.newPage();
|
||||
await invited.goto(`/invitation#${link.split('#')[1]}`);
|
||||
await expect(invited).toHaveURL(/\/groupes$/);
|
||||
await invited.goto(DOC);
|
||||
await invited.locator('ul.deep button.row', { hasText: 'Connaissance suffisante' }).first().click();
|
||||
const panel = invited.locator('aside.panel');
|
||||
await expect(panel.getByText('Ici, seuls les membres de la toile de confiance Ğ1 votent', { exact: false })).toBeVisible();
|
||||
await expect(panel.getByRole('button', { name: 'Pour', exact: true })).toHaveCount(0);
|
||||
// In the test group, the same person votes.
|
||||
await invited.goto(TEST_DOC);
|
||||
await invited.locator('ul.deep button.row', { hasText: 'Connaissance suffisante' }).first().click();
|
||||
await expect(invited.locator('aside.panel').getByRole('button', { name: 'Pour', exact: true })).toBeVisible();
|
||||
});
|
||||
|
||||
@@ -255,7 +255,9 @@
|
||||
</div>
|
||||
{#if p.blocked}<p class="warn">{t('vote.blocked')}</p>{/if}
|
||||
|
||||
{#if votable}
|
||||
{#if votable && !view?.canVote}
|
||||
<p class="muted">{t('vote.wotOnly')}</p>
|
||||
{:else if votable}
|
||||
{#if p.myVoteStale}<p class="warn">{t('vote.stale')}</p>{/if}
|
||||
<div class="choice" role="group" aria-label={t('vote.yours')}>
|
||||
<span class="label">{t('vote.yours')}</span>
|
||||
|
||||
@@ -168,6 +168,7 @@ export const en: Messages = {
|
||||
'vote.entered.remove': '“{title}” has been removed from the text in force.',
|
||||
'vote.entered.inertia': 'The inertia of “{title}” has changed.',
|
||||
'vote.closed': 'This version is no longer open for voting.',
|
||||
'vote.wotOnly': 'Here, only members of the Ğ1 web of trust vote: sign in with your Ğ1 key to vote. You can read, propose and flag a contradiction.',
|
||||
|
||||
'inertia.title': 'Inertia',
|
||||
'inertia.explain': 'The higher the inertia, the more votes it takes to change this text when few people vote.',
|
||||
@@ -309,6 +310,7 @@ export const en: Messages = {
|
||||
'error.last_admin': 'At least one administrator must remain.',
|
||||
'error.g1_not_configured': "Ğ1 sign-in isn't active yet.",
|
||||
'error.invitation_invalid': 'This invitation link is no longer valid.',
|
||||
'error.wot_members_only': 'Here, only members of the Ğ1 web of trust vote.',
|
||||
'error.retry': 'Try again',
|
||||
|
||||
'common.cancel': 'Cancel',
|
||||
|
||||
@@ -168,6 +168,7 @@ export const es: Messages = {
|
||||
'vote.entered.remove': '«{title}» se ha retirado del texto en vigor.',
|
||||
'vote.entered.inertia': 'La inercia de «{title}» ha cambiado.',
|
||||
'vote.closed': 'Esta versión ya no está en votación.',
|
||||
'vote.wotOnly': 'Aquí solo votan los miembros de la red de confianza Ğ1: conéctate con tu clave Ğ1 para votar. Puedes leer, proponer y señalar una contradicción.',
|
||||
|
||||
'inertia.title': 'Inercia',
|
||||
'inertia.explain': 'Cuanto más alta es la inercia, más votos hacen falta para cambiar este texto cuando vota poca gente.',
|
||||
@@ -309,6 +310,7 @@ export const es: Messages = {
|
||||
'error.last_admin': 'Debe quedar al menos un administrador.',
|
||||
'error.g1_not_configured': 'La conexión Ğ1 aún no está activa.',
|
||||
'error.invitation_invalid': 'Este enlace de invitación ya no es válido.',
|
||||
'error.wot_members_only': 'Aquí solo votan los miembros de la red de confianza Ğ1.',
|
||||
'error.retry': 'Reintentar',
|
||||
|
||||
'common.cancel': 'Cancelar',
|
||||
|
||||
@@ -171,6 +171,7 @@ export const fr = {
|
||||
'vote.entered.remove': '« {title} » est retiré du texte en vigueur.',
|
||||
'vote.entered.inertia': "L'inertie de « {title} » a changé.",
|
||||
'vote.closed': 'Cette version ne se vote plus.',
|
||||
'vote.wotOnly': 'Ici, seuls les membres de la toile de confiance Ğ1 votent : connecte-toi avec ta clé Ğ1 pour voter. Tu peux lire, proposer et signaler une contradiction.',
|
||||
|
||||
'inertia.title': 'Inertie',
|
||||
'inertia.explain': "Plus l'inertie est haute, plus il faut de voix pour changer ce texte quand peu de gens votent.",
|
||||
@@ -312,6 +313,7 @@ export const fr = {
|
||||
'error.last_admin': 'Il faut garder au moins un administrateur.',
|
||||
'error.g1_not_configured': "La connexion Ğ1 n'est pas encore active.",
|
||||
'error.invitation_invalid': "Ce lien d'invitation n'est plus valable.",
|
||||
'error.wot_members_only': 'Ici, seuls les membres de la toile de confiance Ğ1 votent.',
|
||||
'error.retry': 'Réessayer',
|
||||
|
||||
'common.cancel': 'Annuler',
|
||||
|
||||
@@ -89,6 +89,8 @@ export interface Publication {
|
||||
}
|
||||
|
||||
export interface DocView {
|
||||
/** trustinWallet: where the electorate is the web of trust, only its members vote. */
|
||||
canVote: boolean;
|
||||
doc: {
|
||||
id: string;
|
||||
slug: string;
|
||||
|
||||
Reference in New Issue
Block a user