feat: govern connector configurations and simulations
This commit is contained in:
@@ -0,0 +1,204 @@
|
||||
import { apiFetch, apiPath, type ApiSettings } from "@govoplan/core-webui";
|
||||
|
||||
export type GovernedConnectorSpecification = {
|
||||
provider: string;
|
||||
protocol: string;
|
||||
capabilities: string[];
|
||||
input_schema: Record<string, unknown>;
|
||||
output_schema: Record<string, unknown>;
|
||||
mapping: {
|
||||
version: string;
|
||||
rules: Array<{
|
||||
source: string;
|
||||
target: string;
|
||||
required?: boolean;
|
||||
default?: unknown;
|
||||
}>;
|
||||
};
|
||||
validation_rules: Array<{
|
||||
kind: "required" | "one_of" | "unique";
|
||||
field: string;
|
||||
values?: unknown[];
|
||||
severity: "warning" | "error";
|
||||
code: string;
|
||||
message: string;
|
||||
}>;
|
||||
dry_run: {
|
||||
supported: boolean;
|
||||
simulation_supported: boolean;
|
||||
sample_rows: Array<Record<string, unknown>>;
|
||||
max_items: number;
|
||||
redacted_fields: string[];
|
||||
};
|
||||
audit: {
|
||||
event_prefix: string;
|
||||
expected_events: string[];
|
||||
evidence_fields: string[];
|
||||
};
|
||||
privacy_classification: "public" | "internal" | "confidential" | "restricted";
|
||||
retention_class: string;
|
||||
operational_limits: Record<string, unknown>;
|
||||
retry_policy: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type ConnectorDefinition = {
|
||||
id: string;
|
||||
definition_key: string;
|
||||
name: string;
|
||||
description?: string | null;
|
||||
status: string;
|
||||
current_revision: number;
|
||||
source_package?: string | null;
|
||||
local_definition: boolean;
|
||||
definition_hash: string;
|
||||
specification: GovernedConnectorSpecification;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type ConnectorConfiguration = {
|
||||
id: string;
|
||||
definition_id: string;
|
||||
definition_key: string;
|
||||
definition_name: string;
|
||||
name: string;
|
||||
status: "draft" | "active" | "disabled";
|
||||
endpoint_url?: string | null;
|
||||
credential_ref?: string | null;
|
||||
base_definition_revision: number;
|
||||
latest_definition_revision: number;
|
||||
update_available: boolean;
|
||||
local_overrides: Record<string, unknown>;
|
||||
protected_paths: string[];
|
||||
effective_configuration: GovernedConnectorSpecification;
|
||||
effective_hash: string;
|
||||
resource_revision: number;
|
||||
ambiguity_policy: "manual_review" | "quarantine" | "reject";
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type ConnectorRun = {
|
||||
id: string;
|
||||
configuration_id: string;
|
||||
mode: "dry_run" | "simulation";
|
||||
idempotency_key: string;
|
||||
status: string;
|
||||
review_state: string;
|
||||
definition_revision: number;
|
||||
configuration_revision: number;
|
||||
configuration_hash: string;
|
||||
input_hash: string;
|
||||
summary: Record<string, number | boolean>;
|
||||
effects: Array<Record<string, unknown>>;
|
||||
diagnostics: Array<Record<string, unknown>>;
|
||||
provenance: Record<string, unknown>;
|
||||
reviewed_by?: string | null;
|
||||
reviewed_at?: string | null;
|
||||
review_reason?: string | null;
|
||||
created_at: string;
|
||||
};
|
||||
|
||||
export type ConnectorConfigurationDraft = {
|
||||
name: string;
|
||||
status: ConnectorConfiguration["status"];
|
||||
endpoint_url: string;
|
||||
credential_ref: string;
|
||||
local_overrides: string;
|
||||
ambiguity_policy: ConnectorConfiguration["ambiguity_policy"];
|
||||
};
|
||||
|
||||
const ROOT = "/api/v1/connectors/governed";
|
||||
|
||||
export async function listConnectorDefinitions(
|
||||
settings: ApiSettings
|
||||
): Promise<ConnectorDefinition[]> {
|
||||
const response = await apiFetch<{ items: ConnectorDefinition[] }>(
|
||||
settings,
|
||||
`${ROOT}/definitions`
|
||||
);
|
||||
return response.items;
|
||||
}
|
||||
|
||||
export async function upsertConnectorDefinition(
|
||||
settings: ApiSettings,
|
||||
payload: Record<string, unknown>
|
||||
): Promise<ConnectorDefinition> {
|
||||
return apiFetch(settings, `${ROOT}/definitions`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
|
||||
export async function listConnectorConfigurations(
|
||||
settings: ApiSettings
|
||||
): Promise<ConnectorConfiguration[]> {
|
||||
const response = await apiFetch<{ items: ConnectorConfiguration[] }>(
|
||||
settings,
|
||||
`${ROOT}/configurations`
|
||||
);
|
||||
return response.items;
|
||||
}
|
||||
|
||||
export function createConnectorConfiguration(
|
||||
settings: ApiSettings,
|
||||
payload: Record<string, unknown>
|
||||
): Promise<ConnectorConfiguration> {
|
||||
return apiFetch(settings, `${ROOT}/configurations`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
|
||||
export function updateConnectorConfiguration(
|
||||
settings: ApiSettings,
|
||||
configurationId: string,
|
||||
payload: Record<string, unknown>
|
||||
): Promise<ConnectorConfiguration> {
|
||||
return apiFetch(
|
||||
settings,
|
||||
`${ROOT}/configurations/${encodeURIComponent(configurationId)}`,
|
||||
{ method: "PUT", body: JSON.stringify(payload) }
|
||||
);
|
||||
}
|
||||
|
||||
export async function listConnectorRuns(
|
||||
settings: ApiSettings,
|
||||
configurationId?: string
|
||||
): Promise<ConnectorRun[]> {
|
||||
const response = await apiFetch<{ items: ConnectorRun[] }>(
|
||||
settings,
|
||||
apiPath(`${ROOT}/runs`, {
|
||||
configuration_id: configurationId || undefined,
|
||||
limit: 100
|
||||
})
|
||||
);
|
||||
return response.items;
|
||||
}
|
||||
|
||||
export function executeConnectorRun(
|
||||
settings: ApiSettings,
|
||||
configurationId: string,
|
||||
mode: "dry-runs" | "simulations",
|
||||
payload: Record<string, unknown>
|
||||
): Promise<ConnectorRun> {
|
||||
return apiFetch(
|
||||
settings,
|
||||
`${ROOT}/configurations/${encodeURIComponent(configurationId)}/${mode}`,
|
||||
{ method: "POST", body: JSON.stringify(payload) }
|
||||
);
|
||||
}
|
||||
|
||||
export function reviewConnectorRun(
|
||||
settings: ApiSettings,
|
||||
runId: string,
|
||||
decision: "approved" | "rejected",
|
||||
reason: string
|
||||
): Promise<ConnectorRun> {
|
||||
return apiFetch(
|
||||
settings,
|
||||
`${ROOT}/runs/${encodeURIComponent(runId)}/review`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify({ decision, reason })
|
||||
}
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user