Files
0pt/src/types/source.ts
T
admin 12080fc517 feat(0pt): PII-Gate GDPR-guardrail for personal-data sources (fail-closed)
PiiGateService makes any future personal-data source (ratsit.se and other
directory domains) technically GDPR-OK before the first byte is stored:
- recorded legal basis (art. 6) with basis_ref evidence, no policy => fail-closed
- data minimisation via field allowlist (art. 5(1)(c))
- storage limitation + enforceRetention purge (art. 5(1)(e))
- sha256-only identity keys + log redaction (art. 25/32)
- accessStatement / erase subject-rights surfaces (art. 15/17)
- robots/rate confirmation required for web+api sources; no stealth/bypass
- audit trail via AUD0 at risk L3 (0pt.pii_*)
- gate enabled by default in SourceQueryService

10 new tests; full suite 166 pass | 1 skip; typecheck (blocking gate) clean.
2026-09-15 02:40:52 +02:00

103 lines
3.9 KiB
TypeScript

/**
* src/types/source.ts
* =====================
* 0pt.source.schema.v1 — a registered upstream data source (a database, a
* crawlable web domain, an API, a file drop, …). Owned by SourceService
* (src/services/source-service.ts); referenced by SourceRatePolicy
* (src/types/source-rate-policy.ts) and by the synchronous query path
* (src/services/source-query-service.ts), which reads `source_type` +
* `adapter_id` to decide whether a Source is queryable.
*
* This is a DIFFERENT, newer entity than the static provenance catalog in
* docs/03-data-model.md's `dim_source` table (the ~9-row list of national
* registries served today by GET /api/sources) -- this Source is a per-tenant
* registration of something 0pt can actually connect to. See
* docs/P0_QUERY_SOURCE_FLOW.md and src/services/source-query-service.ts, the
* first real consumer.
*
* `adapter_id` is the seam that lets a "database" source name the concrete
* driver 0pt should use for it (today only "fabric_onelake_sql" is wired on
* the synchronous path — see source-query-service.ts).
*
* `access` mirrors dim_source.access (docs/03-data-model.md) so a Source
* registered here can still be reported against the same legal-sourcing
* vocabulary CLAUDE.md §1 requires everywhere in this repo.
*/
/**
* Union of both source-type vocabularies that existed in this repo's two
* remotes; nothing is dropped by the unification merge.
*/
export type SourceType = "database" | "file" | "web" | "api" | "stream" | "manual";
/**
* Union of both status vocabularies. "archived" and "deprecated" both survive
* the unification merge -- they were introduced independently and no code
* treats either as canonical.
*
* "pending" (P060) is the state every newly registered source starts in. It
* exists because "active" used to be the CREATE default
* (postgres-source-repository.ts / in-memory-source-repository.ts both did
* `input.status ?? "active"`), which meant a source with no rights, no
* provenance and no authorization was live the instant it was registered.
* Reaching "active" now requires passing SourceRegistryService.activateSource's
* classification gate.
*/
export type SourceStatus = "pending" | "active" | "paused" | "archived" | "deprecated";
/** Legal-sourcing vocabulary, mirroring dim_source.access. */
export type SourceAccess = "api" | "bulk" | "authorized_web" | "licensed";
export interface Source {
source_id: string;
tenant_id: string;
project_id: string;
source_type: SourceType;
name: string;
/**
* Identifies which concrete adapter implementation this source is queried
* through (e.g. "fabric_onelake_sql" -- src/adapters/fabric-onelake-adapter.ts).
* Required in practice for source_type "database"; optional/unused for other
* types until they grow a synchronous query path of their own.
*/
adapter_id?: string;
/** Mirrors dim_source.access (docs/03-data-model.md). */
access?: SourceAccess;
/**
* Explicit self-flag that this source CAN expose personuppgifter. When
* true (or when the source is a known directory domain like ratsit.se),
* the PiiGateService requires a PiiPolicy with a recorded lawful basis
* before any storage/query (fail-closed, GDPR art. 6).
*/
touches_personal_data?: boolean;
description?: string;
status: SourceStatus;
correlation_id?: string;
created_at: string;
updated_at?: string;
/** Who registered the source. */
created_by?: string;
/**
* Who is ACCOUNTABLE for the source going forward (P060 "owner"). Distinct
* from `created_by`, which is only who typed the registration. Required by
* the activation gate.
*/
owner_id?: string;
}
export interface CreateSourceInput {
source_id: string;
tenant_id: string;
project_id: string;
source_type: SourceType;
name: string;
adapter_id?: string;
access?: SourceAccess;
touches_personal_data?: boolean;
description?: string;
status?: SourceStatus;
correlation_id?: string;
created_by?: string;
owner_id?: string;
}