Ctrl K
ComunidadGuías…

scripts/__tests__/skills-admin.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { createHash } from 'node:crypto'
import yaml from 'js-yaml'
import { createQueuedMockSupabase } from '@/tests/helpers'

vi.mock('@supabase/supabase-js', () => ({ createClient: vi.fn() }))
vi.mock('node:fs/promises', () => ({ writeFile: vi.fn(), mkdir: vi.fn() }))
vi.mock('node:child_process', () => ({ execFileSync: vi.fn() }))
import { createClient } from '@supabase/supabase-js'
import { writeFile } from 'node:fs/promises'
import { execFileSync } from 'node:child_process'
import { runSkillsAdmin } from '../skills-admin'

const { supabase, enqueue, reset, findCall, findCalls } = createQueuedMockSupabase()
const id = 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa'
const body = 'Explain the evidence. Stage changes for approval.'
const bodyHash = createHash('sha256').update(body).digest('hex')
const submission = { id, body, submission_body_hash: bodyHash, name: 'Review workflow', description: 'Explain scoped proposals.', author_handle: 'public-author', share_confirmed_at: '2026-09-17', share_status: 'submitted', company_id: 'PRIVATE-COMPANY', created_by: 'PRIVATE-USER', published_atom_id: null }
const entry = { author: submission.author_handle, submissionHash: bodyHash, title: submission.name, description: submission.description, mcp_exposed: true, reviewedAt: '2026-09-17' }
const env = { SKILLS_SUPABASE_URL: 'https://metjnjrhvujscngnpzdv.supabase.co', SKILLS_SERVICE_ROLE_KEY: 'test-only' }
const run = (args: string[]) => runSkillsAdmin([...args, '--project', 'metjnjrhvujscngnpzdv'], env, '/fixture')
const markdown = (data: object) => `---\n${yaml.dump(data)}---\n\nPublic summary.\n`

beforeEach(() => {
  vi.clearAllMocks(); reset()
  vi.mocked(createClient).mockReturnValue(supabase as never)
  vi.mocked(writeFile).mockResolvedValue(undefined)
  vi.spyOn(console, 'log').mockImplementation(() => {})
})
afterEach(() => vi.restoreAllMocks())

describe('local human-gated skill review', () => {
  it('requires explicit matching credentials and specific production write approval', async () => {
    await expect(runSkillsAdmin(['list', '--project', 'different'], env)).rejects.toThrow('matching project')
    await expect(runSkillsAdmin(['disable', '--project', 'pwxtzglxptnnvjrpixpg', '--slug', 'community/test'], { ...env, SKILLS_SUPABASE_URL: 'https://pwxtzglxptnnvjrpixpg.supabase.co' })).rejects.toThrow('production write approval')
    expect(supabase.from).not.toHaveBeenCalled()
  })
  it('exports only reviewed public fields, never tenant or user identifiers', async () => {
    enqueue({ data: submission })
    await run(['prepare', '--id', id, '--slug', 'review-workflow', '--reviewed-at', '2026-09-17', '--review-confirmed'])
    const writes = vi.mocked(writeFile).mock.calls
    expect(writes).toHaveLength(3)
    const content = writes.map((call) => String(call[1])).join('\n')
    expect(content).toContain('public-author')
    expect(content).toContain(bodyHash)
    expect(content).not.toContain('PRIVATE-')
    expect(content).not.toContain(id)
    expect(writes.every((call) => (call[2] as { flag: string }).flag === 'wx')).toBe(true)
    expect(findCall('company_skills', 'update')).toBeUndefined()
    expect(execFileSync).not.toHaveBeenCalled()
  })
  it('rejects changed submitted text before any public file is written', async () => {
    enqueue({ data: { ...submission, body: 'Changed after consent' } })
    await expect(run(['prepare', '--id', id, '--slug', 'review-workflow', '--reviewed-at', '2026-09-17', '--review-confirmed'])).rejects.toThrow('frozen submission')
    expect(writeFile).not.toHaveBeenCalled()
  })
  it('has no withdraw command: the author\'s withdrawal hides the text in the database', async () => {
    await expect(run(['withdraw', '--id', id, '--slug', 'review-workflow'])).rejects.toThrow('Unknown command')
    expect(findCall('agent_atom_registry', 'update')).toBeUndefined()
  })
  it('does not report an open PR as published', async () => {
    enqueue({ data: submission })
    vi.mocked(execFileSync).mockReturnValue(JSON.stringify({ state: 'OPEN', mergeCommit: null, files: [] }))
    await expect(run(['published', '--id', id, '--slug', 'review-workflow', '--pr', '123'])).rejects.toThrow('not merged')
    expect(findCall('company_skills', 'update')).toBeUndefined()
  })
  it('requires merged attribution and deployed body before marking published', async () => {
    enqueue({ data: submission }); enqueue({ data: { body, reviewed_at: '2026-09-17T00:00:00+00:00' } }); enqueue({ data: { id } })
    vi.mocked(execFileSync)
      .mockReturnValueOnce(JSON.stringify({ state: 'MERGED', mergeCommit: { oid: 'commit' }, files: [{ path: 'registry/skills/review-workflow/SKILL.md' }, { path: 'registry/entries/review-workflow.mdx' }] }))
      .mockReturnValueOnce(JSON.stringify({ content: Buffer.from(body).toString('base64') }))
      .mockReturnValueOnce(JSON.stringify({ content: Buffer.from(markdown(entry)).toString('base64') }))
    await run(['published', '--id', id, '--slug', 'review-workflow', '--pr', '123'])
    expect(findCall('company_skills', 'update')?.[0]).toMatchObject({ share_status: 'published', published_atom_id: 'community/review-workflow', reviewed_at: '2026-09-17T00:00:00+00:00' })
    expect(findCalls('company_skills', 'eq')).toContainEqual(['submission_body_hash', bodyHash])
    expect(findCalls('company_skills', 'eq')).toContainEqual(['share_status', 'submitted'])
  })
})