containment 2/2: kind 10050 (inbox relays) + drafts summary in supervisor DM + grants suspended, BTCPay priority-1
ci / lint-test-leaks (pull_request) Canceled after 0s
ci / lint-test-leaks (pull_request) Canceled after 0s
- publish-10050.mjs: publishes Cayce kind 10050 (NIP-65 message-relays/ inbox) listing the 6 relays where the listener actually reads DMs. EXECUTED once with operator authorization: event id 188ef397824e8f29b5e1bea661ae65b1f8532ee97617747b9fbde57c6e8dfce9, accepted 6/6 relays. - initiative.mjs: the cycle DM to the supervisor now includes a summary of outbound_drafts from the last 24h (id, type, first 15 words) so the operator reviews what the agent WANTED to publish. - initiative.mjs: supervisor directive (CAYCE_DIRECTIVE_BTCPAY=1, reversible) injected into the cycle prompt: grants/opportunity search SUSPENDED, single priority = consolidate the BTCPay Server proposal (opportunity #106 / draft #33) ready for HUMAN sending. MANDATE text untouched (only the supervisor can change it). - initiative.mjs: add_opportunity now rejects duplicates (the agent had re-registered OpenSats ×10, HRF ×6). - opportunity #106 status -> priority-1. - check-relay-silence.mjs: queries the relays for Cayce-signed events since a timestamp; allows only kind 10050 and supervisor DMs; exits 1 on any violation. Verified: 0 events, 0 violations since deployment. - deploy.sh: sudo for the daemon restart, optional files tolerated. Gate: make check green (96 tests).
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// check-relay-silence — verifica que Cayce NO publique a relays desde <T>.
|
||||
// Uso: node check-relay-silence.mjs <epoch-segundos-desde> [horas-ventana]
|
||||
// Eventos permitidos: kind 10050 (inbox relays, autorizado), kind 4/1059
|
||||
// (DMs AL SUPERVISOR — canal interno autorizado). Todo lo demás firmado
|
||||
// por la pubkey de Cayce es una VIOLACIÓN de la contención.
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { SimplePool, getPublicKey } from 'nostr-tools'
|
||||
|
||||
const env = Object.fromEntries(
|
||||
readFileSync('/srv/cayce-nostr/.env', 'utf8').split('\n').filter(l => l.includes('=')).map(l => [l.slice(0, l.indexOf('=')), l.slice(l.indexOf('=') + 1)])
|
||||
)
|
||||
// decodificar nsec (bech32 o hex) — mismo approach verificado en publish-10050
|
||||
let sk
|
||||
{
|
||||
const { nsecDeserialize } = await import('nostr-tools')
|
||||
sk = env.NSEC_HEX.startsWith('nsec1') ? nsecDeserialize(env.NSEC_HEX) : Buffer.from(env.NSEC_HEX, 'hex')
|
||||
}
|
||||
const RELAYS = (env.RELAYS || 'wss://relay.damus.io,wss://nos.lol,wss://relay.primal.net,wss://relay.snort.social,wss://nostr-pub.wellorder.net').split(',').map(s => s.trim())
|
||||
const pk = getPublicKey(sk)
|
||||
|
||||
const sinceArg = Number(process.argv[2])
|
||||
const hours = Number(process.argv[3] || 24)
|
||||
if (!sinceArg) { console.error('uso: node check-relay-silence.mjs <epoch_s> [horas]'); process.exit(2) }
|
||||
const T = sinceArg
|
||||
console.log(`[silence] ventanas: eventos de Cayce desde ${new Date(T * 1000).toISOString()} (últimas ${hours}h)`)
|
||||
|
||||
console.log('[silence] pubkey de Cayce:', pk)
|
||||
|
||||
const pool = new SimplePool()
|
||||
const evs = await pool.querySync(RELAYS, { authors: [pk], since: T }, 8000).catch(() => [])
|
||||
pool.close(RELAYS)
|
||||
|
||||
const supervisor = env.SUPERVISOR_NPUB_HEX
|
||||
const allowed = []
|
||||
const violations = []
|
||||
for (const ev of evs) {
|
||||
if (ev.kind === 10050) { allowed.push(ev); continue }
|
||||
if ((ev.kind === 4 || ev.kind === 1059) && supervisor && ev.tags.some(t => t[0] === 'p' && t[1] === supervisor)) { allowed.push(ev); continue }
|
||||
violations.push(ev)
|
||||
}
|
||||
console.log(`[silence] eventos vistos: ${evs.length} · permitidos: ${allowed.length} (10050/DM-supervisor) · VIOLACIONES: ${violations.length}`)
|
||||
for (const ev of violations.slice(0, 10)) {
|
||||
console.log(` ✗ kind ${ev.kind} ${new Date(ev.created_at * 1000).toISOString()} ${ev.id.slice(0, 12)} — ${ev.content.slice(0, 60)}`)
|
||||
}
|
||||
process.exit(violations.length ? 1 : 0)
|
||||
Reference in New Issue
Block a user