Regression-test the full DAO/governance/work-market surface across the live
orgs, read-only (no txs/writes/signing), asserting REAL functionality:
- 30-dao-onchain: BountyV1/ReputationV1/Governor/Safe on Zoo 200200 + Pars
494949 via eth_call/eth_getCode — code present, bountyCount>=1, stateOf(0)==
Paid(6), treasury()==org DAO Safe, ReputationV1.writer()==BountyV1 (wiring).
Lux 96369: canonical CREATE2 Safe suite present, dead Governor asserted 0-byte
(staged post-flag-day). Hanzo 36963 skip-gated until deploy lands.
- 31-vote-surfaces: lux/zoo/hanzo/pars.vote render + correct brand + ZERO cross-
brand/competitor leakage + no white-screen (#root descendants + body text) +
Connect Wallet present. reads-chain gated skip-until-live (Decent-fork shells).
- 32-work-boards: work.zoo.network LIVE badge (green, not FIXTURE), bounty in
Paid column, on-chain ReputationV1 block, UI bounty count == chain bountyCount.
work.{lux,hanzo,pars} skip-until-live.
- 33-bounty-bot: bounties.zoo.network webhook routed+POST-only (405), unsigned
POST rejected (401), healthz internal-scoped (404 public correct). No secrets.
- 34-pars-chain: Pars 494949 chainId + monotonic height + explorer renders.
helpers.ts: additive ethCall/ethGetCode/hasCode/decodeAddress/encodeUint +
HANZO/PARS API domains + orgRpc() (one way to resolve any org's C-Chain RPC).
17-governance: drop dead unused SELECTORS block (on-chain contract asserts now
own their home in 30-dao-onchain). package.json: wire specs into test:full +
per-spec scripts.
36 active tests pass live, 8 skip-gated (ready to flip). Suite stays GREEN.
Co-authored-by: Hanzo Dev <[email protected]>
52 lines
2.7 KiB
TypeScript
52 lines
2.7 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { httpStatus } from './helpers'
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Bounty bot — bounties.zoo.network (GitHub → BountyV1 automation service)
|
|
// ---------------------------------------------------------------------------
|
|
// Read-only liveness probes. No secrets are sent or asserted. We assert the
|
|
// service is ROUTED and ALIVE by its method/scope contract, not by a 200:
|
|
// • GET /v1/github/webhook → 405 — the route exists but is POST-only, so a GET
|
|
// is Method-Not-Allowed. This proves the handler is wired and reachable.
|
|
// • POST /v1/github/webhook (unsigned) → 401 — the handler runs and REJECTS an
|
|
// unauthenticated delivery (HMAC signature missing). Proves it's alive and
|
|
// gated, without needing or revealing the webhook secret.
|
|
// • GET /v1/healthz → 404 — healthz is internal-scoped (cluster probe only), so
|
|
// a 404 from the public edge is the CORRECT, expected answer. A 200 here would
|
|
// mean the internal health surface leaked publicly.
|
|
|
|
const BASE = 'https://bounties.zoo.network'
|
|
|
|
test.describe('Bounty Bot — bounties.zoo.network', () => {
|
|
test('GET /v1/github/webhook is routed and POST-only (405)', async ({ request }) => {
|
|
const status = await httpStatus(request, `${BASE}/v1/github/webhook`)
|
|
console.log(` GET /v1/github/webhook → ${status} (expected 405, POST-only)`)
|
|
expect(status).toBe(405)
|
|
})
|
|
|
|
test('unsigned POST /v1/github/webhook is rejected (401), handler alive', async ({ request }) => {
|
|
// Empty body, no X-Hub-Signature-256 — the service must refuse it.
|
|
const res = await request.post(`${BASE}/v1/github/webhook`, {
|
|
data: {},
|
|
headers: { 'Content-Type': 'application/json' },
|
|
ignoreHTTPSErrors: true,
|
|
timeout: 15_000,
|
|
})
|
|
const status = res.status()
|
|
console.log(` POST /v1/github/webhook (unsigned) → ${status}`)
|
|
// 401 today (signature required). Accept the auth-reject family so a tightened
|
|
// gate (403) or a body-shape reject (400) still passes — never a 2xx (which
|
|
// would mean an unauthenticated delivery was accepted).
|
|
expect([400, 401, 403]).toContain(status)
|
|
expect(status).toBeLessThan(500)
|
|
})
|
|
|
|
test('GET /v1/healthz is internal-scoped (404 public is correct)', async ({ request }) => {
|
|
const status = await httpStatus(request, `${BASE}/v1/healthz`)
|
|
console.log(` GET /v1/healthz → ${status} (expected 404 — internal-scoped, not public)`)
|
|
// 404 is the CORRECT public answer: healthz serves cluster probes only. If this
|
|
// ever returns 200 the internal health surface has been exposed publicly.
|
|
expect(status).toBe(404)
|
|
})
|
|
})
|