Files
iios/packages/iios-service/src/main.ts
T
maaz519 ba745bb71a feat(iios): policy-enforced membership + threaded replies + dev IdP (generic)
Enriches the platform PLANE, not the kernel:
- DevOpaPort: the dev OPA stub now evaluates a small policy table (behind the
  same opa.decide) — DM capped at 2, add-participant requires member/group-admin,
  governed self-join for membership threads. Real OPA swaps in unchanged.
- Dev IdP login (POST /v1/dev/login) issues the same JWT claims a real IdP would.
- PolicyDeniedFilter maps fail-closed denials to HTTP 403.

Generic kernel additions (no chat vocabulary — 'dm'/'group' live only as OPA
policy + an opaque thread attribute):
- MessageService.addParticipant (governed membership by userId), governed
  openThread self-join (scoped to threads with a membership attribute),
  parentInteractionId on send (reply link), and a generic listThreads.
- REST: GET /v1/threads, POST /v1/threads, POST /v1/threads/:id/participants;
  socket add_participant + membership/parentInteractionId. ensureParticipant
  gains a role.

Tests: dev-opa.port.spec + message.spec (DM cap / group admin / governed join /
listThreads / reply). smoke-membership.mjs; realtime smokes updated for governed
join. 175 unit tests + all smokes green; kernel free of dm/group literals.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 16:27:47 +05:30

34 lines
1.4 KiB
TypeScript

import 'dotenv/config';
import 'reflect-metadata';
import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
import { traceMiddleware } from './observability/trace.middleware';
import { RedisIoAdapter } from './realtime/redis-io.adapter';
import { PolicyDeniedFilter } from './platform/policy-denied.filter';
async function bootstrap(): Promise<void> {
const app = await NestFactory.create(AppModule, { rawBody: true });
app.use(traceMiddleware); // request-scoped trace context + x-trace-id header (P9)
app.useGlobalPipes(
new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }),
);
app.useGlobalFilters(new PolicyDeniedFilter()); // fail-closed policy denials → 403
app.enableCors({ origin: true, credentials: true });
// Multi-replica realtime: fan socket.io room emits across instances via Redis.
// Opt-in — without REDIS_URL the default in-memory adapter is used (single instance).
if (process.env.REDIS_URL) {
const redisAdapter = new RedisIoAdapter(app, process.env.REDIS_URL);
await redisAdapter.connect();
app.useWebSocketAdapter(redisAdapter);
}
const port = Number(process.env.PORT ?? 3200);
await app.listen(port);
// eslint-disable-next-line no-console
console.log(`iios-service listening on :${port}`);
}
void bootstrap();