// v1.13.17-cross-repo-reads: PATCH /api/sessions/:id allowed_read_paths
// subset enforcement. Sam flagged in the compliance review that without a
// runtime subset check, a malicious client could POST
//   {"allowed_read_paths":["/etc"]}
// and bypass the user-consent grant flow entirely. The findUnauthorizedAdditions
// helper is the guard; tests pin its behavior so a regression in the helper
// or its callsite (PATCH handler in sessions.ts) trips CI before prod.

import { describe, it, expect } from 'vitest';
import { findUnauthorizedAdditions } from '../sessions.js';

describe('findUnauthorizedAdditions — PATCH allowed_read_paths subset guard', () => {
  it('returns no extras when requested is empty (full revoke)', () => {
    expect(findUnauthorizedAdditions(['/opt/forks/foo'], [])).toEqual([]);
  });

  it('returns no extras when requested is a strict subset (single revoke)', () => {
    expect(
      findUnauthorizedAdditions(['/opt/forks/foo', '/opt/forks/bar'], ['/opt/forks/foo']),
    ).toEqual([]);
  });

  it('returns no extras when requested equals prior (no-op PATCH)', () => {
    expect(
      findUnauthorizedAdditions(['/opt/forks/foo', '/opt/forks/bar'], [
        '/opt/forks/foo',
        '/opt/forks/bar',
      ]),
    ).toEqual([]);
  });

  it('flags an unauthorized addition when prior is empty', () => {
    // The /etc bypass attempt — Sam's specific concern from the compliance
    // review. Without this guard, the PATCH would have written /etc directly.
    expect(findUnauthorizedAdditions([], ['/etc'])).toEqual(['/etc']);
  });

  it('flags a single unauthorized addition mixed in with valid revokes', () => {
    // The attacker still tries to be sneaky: keep one legit entry, drop
    // another, slip in a new one. The guard catches the addition regardless
    // of how the rest of the array shrinks.
    expect(
      findUnauthorizedAdditions(['/opt/forks/foo', '/opt/forks/bar'], [
        '/opt/forks/foo',
        '/var/secrets',
      ]),
    ).toEqual(['/var/secrets']);
  });

  it('flags every unauthorized addition when there are multiple', () => {
    expect(
      findUnauthorizedAdditions(['/opt/forks/foo'], ['/opt/forks/foo', '/etc', '/root']),
    ).toEqual(['/etc', '/root']);
  });

  it('treats requested duplicates correctly (each occurrence checked)', () => {
    // If the requested array has duplicates of an unauthorized entry, the
    // guard surfaces each one. (A frontend would never send duplicates, but
    // the guard's contract shouldn't assume that.)
    expect(findUnauthorizedAdditions([], ['/etc', '/etc'])).toEqual(['/etc', '/etc']);
  });

  it('does not flag entries present in prior even if requested has duplicates', () => {
    // Duplicate of an authorized entry passes — the membership check is by
    // value, not by index. Settled by Set.has semantics.
    expect(
      findUnauthorizedAdditions(['/opt/forks/foo'], ['/opt/forks/foo', '/opt/forks/foo']),
    ).toEqual([]);
  });
});
