Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

225 lines
15 KiB
JSON

[
{
"id": "T001",
"description": "Unit (vitest, packages/email/src/__tests__/TokenBucketRateLimiter.namespaces.test.ts): same (tenant='t1', userId=undefined) in namespace 'email' and namespace 'api' produce two independent buckets — exhaust 'email' bucket, then 'api' bucket still allows tryConsume.",
"implemented": true,
"featureIds": ["F001", "F003"]
},
{
"id": "T002",
"description": "Unit (vitest, packages/email/src/__tests__/TokenBucketRateLimiter.subjectId.test.ts): the registered BucketConfigGetter for namespace 'api' is invoked with both tenantId and subjectId; getter returns per-key configs and the bucket key uses the subjectId as the third dimension.",
"implemented": true,
"featureIds": ["F002", "F003"]
},
{
"id": "T003",
"description": "Unit (vitest, packages/email/src/__tests__/TokenBucketRateLimiter.email-regression.test.ts): with namespace 'email' and a getter returning the same config the existing email path used (maxTokens=60, refillRate=1), tryConsume behavior matches a baseline snapshot of consumption + refill across 1, 30, 60, and 61 calls.",
"implemented": true,
"featureIds": ["F001", "F002", "F005"]
},
{
"id": "T004",
"description": "Unit (vitest, server/src/lib/api/rateLimit/__tests__/configGetter.cache.test.ts): two consecutive apiRateLimitConfigGetter('t1','k1') calls hit the DAL exactly once (mock counts calls).",
"implemented": true,
"featureIds": ["F011"]
},
{
"id": "T005",
"description": "Unit (vitest, server/src/lib/api/rateLimit/__tests__/configGetter.invalidate.test.ts): invalidateApiRateLimitConfig('t1') clears all cached entries whose key starts with 't1:' and leaves other tenants intact; invalidateApiRateLimitConfig('t1','k1') clears only that one entry.",
"implemented": true,
"featureIds": ["F011"]
},
{
"id": "T006",
"description": "Unit (vitest, server/src/lib/api/rateLimit/__tests__/configGetter.fallback.test.ts): with no row → returns hard defaults {120, 1.0}; with a (tenant, NULL) row → returns that row; with a (tenant, apiKeyId) row → returns the per-key row over the tenant default.",
"implemented": true,
"featureIds": ["F010"]
},
{
"id": "T007",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.headers.test.ts): with maxTokens=120, refillRate=1, hit a TicketController-backed route 121 times under one (tenant, apiKeyId); call #121 returns 429 with Retry-After (integer seconds), X-RateLimit-Limit=120, X-RateLimit-Remaining=0, X-RateLimit-Reset (ISO8601 in the future), and body envelope { error: { code: 'RATE_LIMITED', details: { retry_after_ms, remaining: 0 } } }.",
"implemented": true,
"featureIds": ["F006", "F012", "F016", "F017"]
},
{
"id": "T008",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.successHeaders.test.ts): a successful authenticated GET returns X-RateLimit-Limit and X-RateLimit-Remaining headers reflecting the bucket state at decision time.",
"implemented": true,
"featureIds": ["F007", "F019"]
},
{
"id": "T009",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.keyIsolation.test.ts): two API keys K1 and K2 in the same tenant with maxTokens=5; exhaust K1; call #6 with K1 → 429, but call #1 with K2 → 200.",
"implemented": true,
"featureIds": ["F012", "F017"]
},
{
"id": "T010",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.tenantIsolation.test.ts): exhausting tenant A's bucket does not affect tenant B's bucket for the same logical apiKeyId value.",
"implemented": true,
"featureIds": ["F012"]
},
{
"id": "T011",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.bypass.test.ts): a request to /api/v1/health (or a route in the bypass list) does not consume tokens — verify by exhausting the bucket via /api/v1/tickets and then issuing 5 health calls that all return 200.",
"implemented": true,
"featureIds": ["F015"]
},
{
"id": "T012",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.observation.test.ts): with RATE_LIMIT_ENFORCE=false, the 121st call returns 200 with X-RateLimit-Remaining=0 AND a structured WARN log line is emitted containing tenant, api_key_id, retry_after_ms.",
"implemented": true,
"featureIds": ["F013", "F049"]
},
{
"id": "T013",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.failOpen.test.ts): stop the Redis client (connection.disconnect or a mock that throws), make 200 calls, all return 200 with X-RateLimit-Remaining=-1; api_rate_limit_redis_unavailable_total counter incremented.",
"implemented": true,
"featureIds": ["F012", "F049"]
},
{
"id": "T014",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.authSurfaces.test.ts): exhaust the bucket via three different routes — one ApiBaseController-backed (e.g., /api/v1/tickets), one withApiKeyAuth-wrapped (e.g., /api/v1/service-types), and one withAuth-wrapped (/api/v1/test-auth) — all three return 429 from the same shared bucket.",
"implemented": true,
"featureIds": ["F017", "F018"]
},
{
"id": "T015",
"description": "Integration (vitest + real Redis, server/src/test/integration/apiRateLimit.nmStore.test.ts): NM Store global key + x-tenant-id header consumes from the 'nm_store' subjectId bucket; non-NM-Store key in the same tenant is unaffected.",
"implemented": true,
"featureIds": ["F014", "F018"]
},
{
"id": "T016",
"description": "Integration (vitest + real Postgres + real Redis, server/src/test/integration/apiRateLimit.dbOverride.test.ts): seed an api_rate_limit_settings row (tenant='tA', api_key_id='k1', max_tokens=3, refill_per_min=60); call #4 with K1 returns 429; call #1 with a different key in tenant 'tA' returns 200 (uses tenant default = 120 since no (tA, NULL) row).",
"implemented": true,
"featureIds": ["F008", "F009", "F010", "F012"]
},
{
"id": "T017",
"description": "Integration (vitest + real Postgres, server/src/test/integration/apiRateLimit.dbActions.test.ts): setApiRateLimitForKey writes the row and invalidates the cache (subsequent enforce call sees new limit immediately, not after 30s); clearApiRateLimitForKey reverts to tenant default.",
"implemented": true,
"featureIds": ["F021"]
},
{
"id": "T018",
"description": "Unit (vitest, server/src/lib/api/schemas/__tests__/webhookSchemas.test.ts): webhookEventTypeSchema.safeParse('ticket.comment.added').success === true.",
"implemented": true,
"featureIds": ["F023"]
},
{
"id": "T019",
"description": "Unit (vitest, server/src/lib/eventBus/subscribers/webhook/__tests__/webhookEventMap.test.ts): a table-driven test asserts each TICKET_* internal event maps to the documented public event(s); unknown event types return [].",
"implemented": true,
"featureIds": ["F032"]
},
{
"id": "T020",
"description": "Unit (vitest, server/src/lib/eventBus/subscribers/webhook/__tests__/webhookTicketPayload.test.ts): buildTicketWebhookPayload(TICKET_ASSIGNED, knex) returns the documented field set, no undefined leaks, tags is always an array (even when empty); calling it twice within 60s for the same ticket_id+tenant performs the join only once (in-memory cache hit).",
"implemented": true,
"featureIds": ["F033"]
},
{
"id": "T021",
"description": "Unit (vitest, server/src/lib/eventBus/subscribers/webhook/__tests__/webhookTicketPayload.statusChanged.test.ts): for a TICKET_STATUS_CHANGED event with payload.changes.status_id={ from, to }, the public payload includes previous_status_id and previous_status_name resolved from the from value.",
"implemented": true,
"featureIds": ["F033", "F034"]
},
{
"id": "T022",
"description": "Unit (vitest, server/src/lib/eventBus/subscribers/webhook/__tests__/webhookTicketPayload.comment.test.ts): for TICKET_COMMENT_ADDED, the payload includes { comment: { text, author, timestamp, is_internal } } and does NOT include attachments or any field whose key matches /attach/i.",
"implemented": true,
"featureIds": ["F033"]
},
{
"id": "T023",
"description": "Unit (vitest, server/src/lib/webhooks/__tests__/sign.test.ts): golden vector — secret='shh', body='{\"a\":1}', ts=1700000000 produces the documented X-Alga-Signature value (hex); verifyWebhookSignature returns true on the same triple, false on a body byte change, false on ts skewed by ±1.",
"implemented": true,
"featureIds": ["F030", "F043"]
},
{
"id": "T024",
"description": "Unit (vitest, server/src/lib/webhooks/__tests__/ssrf.test.ts): assertSafeWebhookTarget rejects http://127.0.0.1, http://localhost, http://[::1], http://10.0.0.5, http://172.16.5.5, http://192.168.1.1, http://169.254.169.254, http://100.64.0.1, file:///etc/passwd, ftp://example.com — and accepts https://example.com. With WEBHOOK_SSRF_ALLOW_PRIVATE=true, the private addresses pass.",
"implemented": true,
"featureIds": ["F029"]
},
{
"id": "T025",
"description": "Integration (vitest + real Redis + ephemeral http server, server/src/test/integration/webhookDelivery.happyPath.test.ts): create a webhook subscribed to ticket.assigned in tenant A; publishEvent({ eventType:'TICKET_ASSIGNED', payload:{ tenantId:'A', ticket_id, ... } }); wait for the WebhookDeliveryQueue poller; assert (a) the stub HTTP server receives one POST, (b) the body has the documented envelope { event_id, event_type:'ticket.assigned', occurred_at, tenant_id:'A', data }, (c) X-Alga-Signature header verifies, (d) a webhook_deliveries row exists with status='delivered' and attempt_number=1.",
"implemented": true,
"featureIds": ["F024", "F025", "F026", "F027", "F028", "F030", "F032", "F033", "F035", "F036", "F037", "F038"]
},
{
"id": "T026",
"description": "Integration (vitest + real Redis + ephemeral http server, server/src/test/integration/webhookDelivery.tenantIsolation.test.ts): two webhooks — A subscribed to ticket.assigned in tenant TA, B subscribed in tenant TB. Publish TICKET_ASSIGNED with tenantId=TA. Assert webhook A is called once, webhook B is never called, no webhook_deliveries row is created in tenant TB.",
"implemented": true,
"featureIds": ["F035"]
},
{
"id": "T027",
"description": "Integration (vitest + real Redis + http server returning 500, server/src/test/integration/webhookDelivery.retries.test.ts): a delivery to a 500-returning stub triggers 5 attempts; using vitest fake timers, advance through 1m, 5m, 30m, 2h, 12h and assert each attempt fires once and webhook_deliveries.attempt_number progresses 1..5; after the 5th failure the row status becomes 'abandoned' and the ZSET item is removed.",
"implemented": true,
"featureIds": ["F037", "F039"]
},
{
"id": "T028",
"description": "Integration (vitest + fake timers, server/src/test/integration/webhookDelivery.autoDisable.test.ts): with a stub that always returns 500, advance 24h of attempts across multiple events; webhook.is_active becomes false, webhook.auto_disabled_at is set, and an email notification was queued for the owning user.",
"implemented": true,
"featureIds": ["F040"]
},
{
"id": "T029",
"description": "Integration (vitest + real Redis, server/src/test/integration/webhookDelivery.perWebhookRateLimit.test.ts): with webhook.rate_limit_per_min=10, enqueue 30 deliveries simultaneously; assert exactly 10 deliveries fire within the first second and the remaining 20 are re-zAdd-ed with deliverAt scores in the future (asserted by reading the ZSET).",
"implemented": true,
"featureIds": ["F031", "F037"]
},
{
"id": "T030",
"description": "Integration (vitest + 2 simulated workers, server/src/test/integration/webhookDelivery.zsetAtomicity.test.ts): two WebhookDeliveryQueue.process() invocations on the same job (simulating two pods racing). Exactly one zRem returns 1; the other returns 0 and the second worker exits without calling performWebhookDelivery (verified by spy).",
"implemented": true,
"featureIds": ["F037"]
},
{
"id": "T031",
"description": "Integration (vitest, server/src/test/integration/webhookDelivery.ssrf.test.ts): a webhook with url=http://127.0.0.1 fails with an SSRF error before any HTTP socket is opened (spy on undici/fetch confirms zero invocations); the same URL is accepted with WEBHOOK_SSRF_ALLOW_PRIVATE=true.",
"implemented": true,
"featureIds": ["F028", "F029"]
},
{
"id": "T032",
"description": "Integration (vitest + real Postgres, server/src/test/integration/webhook.secretLifecycle.test.ts): POST /api/v1/webhooks returns plaintext signing_secret in the response body once; subsequent GET /api/v1/webhooks/[id] response body does NOT contain any field matching /signing_secret/i; webhookModel.getSigningSecret resolves a non-empty string via the secret provider; rotateWebhookSecret returns a different plaintext, and the OLD plaintext fails verifyWebhookSignature against a body signed by the NEW secret.",
"implemented": true,
"featureIds": ["F024", "F027", "F042", "F043"]
},
{
"id": "T033",
"description": "Integration (vitest + ephemeral http server, server/src/test/integration/webhook.testEndpoint.test.ts): POST /api/v1/webhooks/[id]/test → stub server receives one POST with event_type='webhook.test'; signature verifies; webhook_deliveries row written with is_test=true; bucket token count for the webhook is unchanged (no rate-limit consumption for test calls).",
"implemented": true,
"featureIds": ["F031", "F046"]
},
{
"id": "T034",
"description": "Integration (vitest + ephemeral http server, server/src/test/integration/webhookDelivery.entityIdFilter.test.ts): a webhook with filter.entity_ids=['ticket-X','ticket-Y'] receives a delivery when a TICKET_ASSIGNED event for ticket-X publishes, and does NOT receive one when a TICKET_ASSIGNED event for ticket-Z publishes.",
"implemented": true,
"featureIds": ["F041"]
},
{
"id": "T035",
"description": "Integration (vitest + real Postgres, server/src/test/integration/webhook.cleanupJob.test.ts): seed 100 webhook_deliveries rows with attempted_at spread across 60 days; run the cleanup job once; assert rows older than 30 days are deleted and rows ≤30 days remain.",
"implemented": true,
"featureIds": ["F048"]
},
{
"id": "T036",
"description": "Integration (vitest + real Postgres, server/src/test/integration/webhook.controllerEndpoints.test.ts): exercise getDeliveryDetails (returns a known row by id), getWebhookHealth (computed from stats columns), getWebhookSubscriptions (returns webhook.event_types), listAvailableEvents (returns the public enum). Also assert that DELETED route paths (e.g., /api/v1/webhooks/transform, /webhooks/bulk, /webhooks/templates) return 404 (no longer registered).",
"implemented": true,
"featureIds": ["F044", "F045"]
},
{
"id": "T037",
"description": "Migration smoke (vitest + a fresh test database, server/src/test/integration/migrations.rateLimitAndWebhooks.test.ts): run the new migrations end-to-end; INSERT into api_rate_limit_settings and webhooks/webhook_deliveries succeed; the UNIQUE (tenant, api_key_id) constraint is enforced; a SELECT distribution_column from pg_dist_partition confirms 'tenant' for all three tables.",
"implemented": true,
"featureIds": ["F008", "F009", "F024", "F025", "F026"]
}
]