@obsunified/collector 2.2.3 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts +1 -1
- package/dist/{chunk-ZSF5XP3B.js → chunk-RASSTGNB.js} +30 -22
- package/dist/chunk-RASSTGNB.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2562 -2311
- package/dist/index.js.map +1 -1
- package/dist/{ingest-auth-C5-8Mly5.d.ts → ingest-auth-BmP5-f96.d.ts} +32 -1
- package/dist/{openai-GSJZGFGL.js → openai-VDKVVZAV.js} +2 -2
- package/package.json +4 -2
- package/src/__tests__/autosre-closed-loop.test.ts +110 -0
- package/src/__tests__/db-parity.integration.test.ts +961 -0
- package/src/__tests__/internal-contracts-routes.test.ts +451 -0
- package/src/framework/env.ts +105 -0
- package/src/index.ts +13 -4
- package/src/lib/ai-store/evaluations.test.ts +3 -3
- package/src/lib/analyses-store.test.ts +6 -6
- package/src/lib/db-parity.ts +883 -0
- package/src/lib/eval-cases-store.test.ts +1 -1
- package/src/lib/eval-cases-store.ts +16 -4
- package/src/lib/evidence-references.ts +30 -22
- package/src/lib/stage6.test.ts +1 -1
- package/src/migrations/parity.test.ts +105 -3
- package/src/plugins/ai-receiver.ts +6 -1
- package/src/plugins/autosre-routes.ts +251 -140
- package/src/plugins/connected-routes/manifest.test.ts +114 -32
- package/src/plugins/connected-routes/manifest.ts +59 -76
- package/src/plugins/connected-routes.test.ts +10 -8
- package/src/plugins/connected-routes.ts +42 -12
- package/src/plugins/eval-cases-routes.ts +33 -10
- package/src/plugins/evidence-retrieval-routes.ts +60 -25
- package/dist/chunk-ZSF5XP3B.js.map +0 -1
- /package/dist/{openai-GSJZGFGL.js.map → openai-VDKVVZAV.js.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
CausalProofTier,
|
|
3
2
|
CausalVerificationStatus,
|
|
4
3
|
ChangeEventKind,
|
|
5
|
-
CohortAttributionVerdict,
|
|
6
4
|
EvidenceEntityKind,
|
|
7
5
|
GrantCallbackDelivery,
|
|
8
6
|
GrantDeliveryResult,
|
|
7
|
+
InternalEndpointKey,
|
|
8
|
+
InternalEndpoints,
|
|
9
9
|
InvestigationFindingInput,
|
|
10
10
|
JsonValue,
|
|
11
11
|
RemediationActionKind,
|
|
@@ -14,11 +14,16 @@ import type {
|
|
|
14
14
|
RemediationStateSpec,
|
|
15
15
|
} from "@obsunified/types";
|
|
16
16
|
import {
|
|
17
|
+
ChangeEventInputSchema,
|
|
17
18
|
ChangeEventKindSchema,
|
|
18
19
|
EvidencePredicateSchema,
|
|
20
|
+
InvestigationFindingHttpInputSchema,
|
|
19
21
|
RemediationActionKindSchema,
|
|
22
|
+
RemediationProposalInputSchema,
|
|
23
|
+
validateContractResponse,
|
|
20
24
|
} from "@obsunified/types";
|
|
21
25
|
import { AgentAutonomyLevel } from "@obsunified/types/constants";
|
|
26
|
+
import type { Context } from "hono";
|
|
22
27
|
import type { CollectorPlugin } from "../framework/collector";
|
|
23
28
|
import type { CollectorEnv } from "../framework/env";
|
|
24
29
|
import {
|
|
@@ -64,6 +69,21 @@ import { assertSafeWebhookUrl } from "../lib/webhook-url";
|
|
|
64
69
|
import { getProjectId } from "./_context";
|
|
65
70
|
import { readJsonObject } from "./_json";
|
|
66
71
|
|
|
72
|
+
export function respondWithContract<
|
|
73
|
+
K extends InternalEndpointKey,
|
|
74
|
+
C extends {
|
|
75
|
+
json: (data: unknown, status?: 200 | 201 | 202) => Response;
|
|
76
|
+
},
|
|
77
|
+
>(
|
|
78
|
+
c: C,
|
|
79
|
+
endpoint: K,
|
|
80
|
+
payload: InternalEndpoints[K]["response"],
|
|
81
|
+
status: 200 | 201 | 202 = 200,
|
|
82
|
+
): Response {
|
|
83
|
+
validateContractResponse(endpoint, payload, status);
|
|
84
|
+
return c.json(payload, status);
|
|
85
|
+
}
|
|
86
|
+
|
|
67
87
|
const CHANGE_KINDS = new Set<string>(ChangeEventKindSchema.options);
|
|
68
88
|
|
|
69
89
|
const REMEDIATION_ACTION_KINDS = new Set<string>(
|
|
@@ -300,52 +320,63 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
300
320
|
? body.actor
|
|
301
321
|
: null;
|
|
302
322
|
|
|
323
|
+
const rawInput = {
|
|
324
|
+
id: typeof body.id === "string" ? body.id : undefined,
|
|
325
|
+
environment:
|
|
326
|
+
typeof body.environment === "string" ? body.environment : undefined,
|
|
327
|
+
kind: normalizedKind,
|
|
328
|
+
source:
|
|
329
|
+
body.source === "inferred_telemetry" ||
|
|
330
|
+
body.source === "autosre_remediation" ||
|
|
331
|
+
body.source === "ci_webhook"
|
|
332
|
+
? body.source
|
|
333
|
+
: ("explicit_api" as const),
|
|
334
|
+
targetNodeId:
|
|
335
|
+
typeof body.targetNodeId === "string" ? body.targetNodeId : undefined,
|
|
336
|
+
serviceName,
|
|
337
|
+
namespace,
|
|
338
|
+
version: typeof body.version === "string" ? body.version : null,
|
|
339
|
+
previousVersion:
|
|
340
|
+
typeof body.previousVersion === "string"
|
|
341
|
+
? body.previousVersion
|
|
342
|
+
: null,
|
|
343
|
+
commitSha: typeof body.commitSha === "string" ? body.commitSha : null,
|
|
344
|
+
previousCommitSha:
|
|
345
|
+
typeof body.previousCommitSha === "string"
|
|
346
|
+
? body.previousCommitSha
|
|
347
|
+
: null,
|
|
348
|
+
configDigest:
|
|
349
|
+
typeof body.configDigest === "string" ? body.configDigest : null,
|
|
350
|
+
summary,
|
|
351
|
+
actorId,
|
|
352
|
+
repositoryUrl,
|
|
353
|
+
pullRequestUrl,
|
|
354
|
+
causedByActionId:
|
|
355
|
+
typeof body.causedByActionId === "string"
|
|
356
|
+
? body.causedByActionId
|
|
357
|
+
: null,
|
|
358
|
+
agentRunId:
|
|
359
|
+
typeof body.agentRunId === "string" ? body.agentRunId : null,
|
|
360
|
+
touchedPaths,
|
|
361
|
+
attributes,
|
|
362
|
+
occurredAt:
|
|
363
|
+
typeof body.occurredAt === "string" ? body.occurredAt : undefined,
|
|
364
|
+
};
|
|
365
|
+
const parsedInput = ChangeEventInputSchema.safeParse(rawInput);
|
|
366
|
+
if (!parsedInput.success) {
|
|
367
|
+
return c.json(
|
|
368
|
+
{
|
|
369
|
+
error: parsedInput.error.issues
|
|
370
|
+
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
371
|
+
.join("; "),
|
|
372
|
+
},
|
|
373
|
+
400,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
303
377
|
let changeEvent: Awaited<ReturnType<typeof recordChangeEvent>>;
|
|
304
378
|
try {
|
|
305
|
-
changeEvent = await recordChangeEvent(db, projectId,
|
|
306
|
-
id: typeof body.id === "string" ? body.id : undefined,
|
|
307
|
-
environment:
|
|
308
|
-
typeof body.environment === "string" ? body.environment : undefined,
|
|
309
|
-
kind: normalizedKind,
|
|
310
|
-
source:
|
|
311
|
-
body.source === "inferred_telemetry" ||
|
|
312
|
-
body.source === "autosre_remediation" ||
|
|
313
|
-
body.source === "ci_webhook"
|
|
314
|
-
? body.source
|
|
315
|
-
: "explicit_api",
|
|
316
|
-
targetNodeId:
|
|
317
|
-
typeof body.targetNodeId === "string"
|
|
318
|
-
? body.targetNodeId
|
|
319
|
-
: undefined,
|
|
320
|
-
serviceName,
|
|
321
|
-
namespace,
|
|
322
|
-
version: typeof body.version === "string" ? body.version : null,
|
|
323
|
-
previousVersion:
|
|
324
|
-
typeof body.previousVersion === "string"
|
|
325
|
-
? body.previousVersion
|
|
326
|
-
: null,
|
|
327
|
-
commitSha: typeof body.commitSha === "string" ? body.commitSha : null,
|
|
328
|
-
previousCommitSha:
|
|
329
|
-
typeof body.previousCommitSha === "string"
|
|
330
|
-
? body.previousCommitSha
|
|
331
|
-
: null,
|
|
332
|
-
configDigest:
|
|
333
|
-
typeof body.configDigest === "string" ? body.configDigest : null,
|
|
334
|
-
summary,
|
|
335
|
-
actorId,
|
|
336
|
-
repositoryUrl,
|
|
337
|
-
pullRequestUrl,
|
|
338
|
-
causedByActionId:
|
|
339
|
-
typeof body.causedByActionId === "string"
|
|
340
|
-
? body.causedByActionId
|
|
341
|
-
: null,
|
|
342
|
-
agentRunId:
|
|
343
|
-
typeof body.agentRunId === "string" ? body.agentRunId : null,
|
|
344
|
-
touchedPaths,
|
|
345
|
-
attributes,
|
|
346
|
-
occurredAt:
|
|
347
|
-
typeof body.occurredAt === "string" ? body.occurredAt : undefined,
|
|
348
|
-
});
|
|
379
|
+
changeEvent = await recordChangeEvent(db, projectId, parsedInput.data);
|
|
349
380
|
} catch (err) {
|
|
350
381
|
if (err instanceof InvalidTimestampError) {
|
|
351
382
|
return c.json({ error: err.message }, 400);
|
|
@@ -353,7 +384,12 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
353
384
|
throw err;
|
|
354
385
|
}
|
|
355
386
|
|
|
356
|
-
return
|
|
387
|
+
return respondWithContract(
|
|
388
|
+
c,
|
|
389
|
+
"POST /v1/changes",
|
|
390
|
+
{ ...changeEvent, changeEvent, change: changeEvent },
|
|
391
|
+
201,
|
|
392
|
+
);
|
|
357
393
|
});
|
|
358
394
|
|
|
359
395
|
// 2. Ontology Graph & Fault Localization
|
|
@@ -371,7 +407,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
371
407
|
? await loadTraceFaultLocusFromDb(db, projectId, traceId)
|
|
372
408
|
: null;
|
|
373
409
|
|
|
374
|
-
return c
|
|
410
|
+
return respondWithContract(c, "GET /internal/ontology", {
|
|
375
411
|
...graph,
|
|
376
412
|
faultLocus,
|
|
377
413
|
});
|
|
@@ -398,7 +434,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
398
434
|
since: c.req.query("since") || undefined,
|
|
399
435
|
limit: parseLimit(c.req.query("limit"), 50),
|
|
400
436
|
});
|
|
401
|
-
return c
|
|
437
|
+
return respondWithContract(c, "GET /internal/changes", { changes });
|
|
402
438
|
} catch (err) {
|
|
403
439
|
if (err instanceof InvalidTimestampError) {
|
|
404
440
|
return c.json({ error: err.message }, 400);
|
|
@@ -434,7 +470,10 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
434
470
|
if (!blastRadius) {
|
|
435
471
|
return c.json({ error: "Change event not found" }, 404);
|
|
436
472
|
}
|
|
437
|
-
return c
|
|
473
|
+
return respondWithContract(c, "GET /internal/changes/:id/blast-radius", {
|
|
474
|
+
blastRadius,
|
|
475
|
+
...blastRadius,
|
|
476
|
+
});
|
|
438
477
|
});
|
|
439
478
|
|
|
440
479
|
// 4. Incident Investigations & Lease Coordination
|
|
@@ -447,10 +486,12 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
447
486
|
status: c.req.query("status") || undefined,
|
|
448
487
|
limit: parseLimit(c.req.query("limit"), 50),
|
|
449
488
|
});
|
|
450
|
-
return c
|
|
489
|
+
return respondWithContract(c, "GET /internal/incidents", { incidents });
|
|
451
490
|
});
|
|
452
491
|
|
|
453
|
-
|
|
492
|
+
const openIncidentHandler = async (
|
|
493
|
+
c: Context<{ Bindings: CollectorEnv }>,
|
|
494
|
+
) => {
|
|
454
495
|
const projectId = getProjectId(c);
|
|
455
496
|
const body = await readJsonObject<Record<string, unknown>>(c);
|
|
456
497
|
if (!body) {
|
|
@@ -504,8 +545,15 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
504
545
|
? (body.latestBundle as Record<string, unknown>)
|
|
505
546
|
: null,
|
|
506
547
|
});
|
|
507
|
-
return
|
|
508
|
-
|
|
548
|
+
return respondWithContract(
|
|
549
|
+
c,
|
|
550
|
+
"POST /internal/incidents",
|
|
551
|
+
result,
|
|
552
|
+
result.deduplicated ? 200 : 201,
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
app.post("/internal/incidents", openIncidentHandler);
|
|
556
|
+
app.post("/internal/incidents/open", openIncidentHandler);
|
|
509
557
|
|
|
510
558
|
app.post("/internal/incidents/:id/lease", async (c) => {
|
|
511
559
|
const projectId = getProjectId(c);
|
|
@@ -519,7 +567,9 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
519
567
|
? body.runnerId.trim()
|
|
520
568
|
: typeof body.leaseOwner === "string"
|
|
521
569
|
? body.leaseOwner.trim()
|
|
522
|
-
: ""
|
|
570
|
+
: typeof body.leaseOwnerId === "string"
|
|
571
|
+
? body.leaseOwnerId.trim()
|
|
572
|
+
: "";
|
|
523
573
|
if (!runnerId) {
|
|
524
574
|
return c.json({ error: "runnerId is required" }, 400);
|
|
525
575
|
}
|
|
@@ -531,17 +581,28 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
531
581
|
: typeof body.ttlSeconds === "number" &&
|
|
532
582
|
Number.isFinite(body.ttlSeconds)
|
|
533
583
|
? body.ttlSeconds
|
|
534
|
-
: typeof body.
|
|
535
|
-
Number.isFinite(body.
|
|
536
|
-
?
|
|
537
|
-
:
|
|
584
|
+
: typeof body.leaseSeconds === "number" &&
|
|
585
|
+
Number.isFinite(body.leaseSeconds)
|
|
586
|
+
? body.leaseSeconds
|
|
587
|
+
: typeof body.leaseDurationMs === "number" &&
|
|
588
|
+
Number.isFinite(body.leaseDurationMs)
|
|
589
|
+
? Math.ceil(body.leaseDurationMs / 1000)
|
|
590
|
+
: undefined;
|
|
538
591
|
const result = await acquireIncidentLease(db, projectId, incidentId, {
|
|
539
592
|
environment:
|
|
540
593
|
typeof body.environment === "string" ? body.environment : undefined,
|
|
541
594
|
runnerId,
|
|
542
595
|
leaseDurationSeconds,
|
|
543
596
|
});
|
|
544
|
-
|
|
597
|
+
if (!result.acquired) {
|
|
598
|
+
return c.json(result, 409);
|
|
599
|
+
}
|
|
600
|
+
return respondWithContract(
|
|
601
|
+
c,
|
|
602
|
+
"POST /internal/incidents/:id/lease",
|
|
603
|
+
result,
|
|
604
|
+
200,
|
|
605
|
+
);
|
|
545
606
|
});
|
|
546
607
|
|
|
547
608
|
app.post("/internal/incidents/:id/dispatch", async (c) => {
|
|
@@ -568,7 +629,15 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
568
629
|
allowPrivateNetworks: c.env?.ALERT_WEBHOOK_ALLOW_PRIVATE === "true",
|
|
569
630
|
logger: runtime.logger,
|
|
570
631
|
});
|
|
571
|
-
|
|
632
|
+
if (!result.delivered) {
|
|
633
|
+
return c.json({ ...result, dispatched: result.delivered }, 502);
|
|
634
|
+
}
|
|
635
|
+
return respondWithContract(
|
|
636
|
+
c,
|
|
637
|
+
"POST /internal/incidents/:id/dispatch",
|
|
638
|
+
{ ...result, dispatched: result.delivered },
|
|
639
|
+
200,
|
|
640
|
+
);
|
|
572
641
|
});
|
|
573
642
|
|
|
574
643
|
// 5. Investigation Findings & Counterfactual Verification
|
|
@@ -591,7 +660,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
591
660
|
incidentId: c.req.query("incidentId") || undefined,
|
|
592
661
|
limit: parseLimit(c.req.query("limit"), 20),
|
|
593
662
|
});
|
|
594
|
-
return c
|
|
663
|
+
return respondWithContract(c, "GET /internal/findings", { findings });
|
|
595
664
|
});
|
|
596
665
|
|
|
597
666
|
app.post("/internal/findings", async (c) => {
|
|
@@ -657,72 +726,67 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
657
726
|
}
|
|
658
727
|
}
|
|
659
728
|
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
id: typeof body.id === "string" ? body.id : undefined,
|
|
663
|
-
idempotencyKey:
|
|
664
|
-
typeof body.idempotencyKey === "string" && body.idempotencyKey.trim()
|
|
665
|
-
? body.idempotencyKey.trim()
|
|
666
|
-
: undefined,
|
|
667
|
-
environment:
|
|
668
|
-
typeof body.environment === "string" ? body.environment : undefined,
|
|
669
|
-
incidentId:
|
|
670
|
-
typeof body.incidentId === "string" ? body.incidentId : null,
|
|
671
|
-
fingerprintInput:
|
|
672
|
-
body.fingerprintInput && typeof body.fingerprintInput === "object"
|
|
673
|
-
? (body.fingerprintInput as InvestigationFindingInput["fingerprintInput"])
|
|
674
|
-
: undefined,
|
|
729
|
+
const parsed = InvestigationFindingHttpInputSchema.safeParse({
|
|
730
|
+
...body,
|
|
675
731
|
title,
|
|
676
732
|
summary,
|
|
677
|
-
|
|
678
|
-
typeof body.causalProofTier === "string"
|
|
679
|
-
? (body.causalProofTier as CausalProofTier)
|
|
680
|
-
: undefined,
|
|
681
|
-
confidence:
|
|
682
|
-
typeof body.confidence === "number" ? body.confidence : undefined,
|
|
683
|
-
symptomEntityKind: symptomEntityKind as EvidenceEntityKind,
|
|
733
|
+
symptomEntityKind,
|
|
684
734
|
symptomEntityId,
|
|
685
|
-
faultLocusEntityKind
|
|
735
|
+
faultLocusEntityKind,
|
|
686
736
|
faultLocusEntityId,
|
|
687
|
-
|
|
688
|
-
typeof body.
|
|
689
|
-
?
|
|
690
|
-
:
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
737
|
+
idempotencyKey:
|
|
738
|
+
typeof body.idempotencyKey === "string"
|
|
739
|
+
? body.idempotencyKey.trim() || undefined
|
|
740
|
+
: body.idempotencyKey,
|
|
741
|
+
});
|
|
742
|
+
if (!parsed.success) {
|
|
743
|
+
return c.json(
|
|
744
|
+
{
|
|
745
|
+
error: parsed.error.issues
|
|
746
|
+
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
747
|
+
.join("; "),
|
|
748
|
+
},
|
|
749
|
+
400,
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
const data = parsed.data;
|
|
753
|
+
|
|
754
|
+
const db = sqlDbFor(c.env);
|
|
755
|
+
const input: InvestigationFindingInput = {
|
|
756
|
+
id: data.id,
|
|
757
|
+
idempotencyKey: data.idempotencyKey,
|
|
758
|
+
environment: data.environment,
|
|
759
|
+
incidentId: data.incidentId ?? null,
|
|
760
|
+
fingerprintInput: data.fingerprintInput,
|
|
761
|
+
title: data.title,
|
|
762
|
+
summary: data.summary,
|
|
763
|
+
causalProofTier: data.causalProofTier,
|
|
764
|
+
confidence: data.confidence,
|
|
765
|
+
symptomEntityKind: data.symptomEntityKind,
|
|
766
|
+
symptomEntityId: data.symptomEntityId,
|
|
767
|
+
faultLocusEntityKind: data.faultLocusEntityKind,
|
|
768
|
+
faultLocusEntityId: data.faultLocusEntityId,
|
|
769
|
+
rootCauseEntityKind: data.rootCauseEntityKind ?? null,
|
|
770
|
+
rootCauseEntityId: data.rootCauseEntityId ?? null,
|
|
771
|
+
contributingChangeId: data.contributingChangeId ?? null,
|
|
772
|
+
cohortVerdict: data.cohortVerdict ?? null,
|
|
773
|
+
contendingTraceId: data.contendingTraceId ?? null,
|
|
774
|
+
causalChain: (data.causalChain ??
|
|
775
|
+
[]) as InvestigationFindingInput["causalChain"],
|
|
776
|
+
citedEvidenceIds: data.citedEvidenceIds ?? [],
|
|
777
|
+
codeReferences: data.codeReferences,
|
|
778
|
+
agentRunId: data.agentRunId ?? null,
|
|
720
779
|
};
|
|
721
780
|
|
|
722
781
|
const finding = await recordInvestigationFinding(db, projectId, input, {
|
|
723
782
|
logger: runtime.logger,
|
|
724
783
|
});
|
|
725
|
-
return
|
|
784
|
+
return respondWithContract(
|
|
785
|
+
c,
|
|
786
|
+
"POST /internal/findings",
|
|
787
|
+
{ ...finding, finding, id: finding.id },
|
|
788
|
+
201,
|
|
789
|
+
);
|
|
726
790
|
});
|
|
727
791
|
|
|
728
792
|
app.post("/internal/findings/:id/counterfactual", async (c) => {
|
|
@@ -770,7 +834,15 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
770
834
|
: undefined,
|
|
771
835
|
},
|
|
772
836
|
);
|
|
773
|
-
return
|
|
837
|
+
return respondWithContract(
|
|
838
|
+
c,
|
|
839
|
+
"POST /internal/findings/:id/counterfactual",
|
|
840
|
+
{
|
|
841
|
+
verified: true,
|
|
842
|
+
finding,
|
|
843
|
+
proof: finding.counterfactualProof,
|
|
844
|
+
},
|
|
845
|
+
);
|
|
774
846
|
} catch (err) {
|
|
775
847
|
const message = err instanceof Error ? err.message : String(err);
|
|
776
848
|
if (err instanceof CounterfactualVerificationError) {
|
|
@@ -806,7 +878,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
806
878
|
fail_count: number | null;
|
|
807
879
|
}>();
|
|
808
880
|
if (!row) return c.json({ error: "Eval run not found" }, 404);
|
|
809
|
-
return c
|
|
881
|
+
return respondWithContract(c, "GET /internal/evals/runs/:id", {
|
|
810
882
|
run: {
|
|
811
883
|
id: row.id,
|
|
812
884
|
evalCaseId: row.eval_case_id,
|
|
@@ -832,7 +904,9 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
832
904
|
undefined,
|
|
833
905
|
limit: parseLimit(c.req.query("limit"), 50),
|
|
834
906
|
});
|
|
835
|
-
return c
|
|
907
|
+
return respondWithContract(c, "GET /internal/remediations", {
|
|
908
|
+
proposals,
|
|
909
|
+
});
|
|
836
910
|
});
|
|
837
911
|
|
|
838
912
|
app.post("/internal/remediations/propose", async (c) => {
|
|
@@ -906,7 +980,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
906
980
|
);
|
|
907
981
|
}
|
|
908
982
|
}
|
|
909
|
-
const
|
|
983
|
+
const rawInput: RemediationProposalInput = {
|
|
910
984
|
environment:
|
|
911
985
|
typeof body.environment === "string" ? body.environment : undefined,
|
|
912
986
|
incidentId,
|
|
@@ -918,6 +992,10 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
918
992
|
desiredTargetState,
|
|
919
993
|
requestedAutonomy,
|
|
920
994
|
};
|
|
995
|
+
const parsedInput = RemediationProposalInputSchema.safeParse(rawInput);
|
|
996
|
+
const input: RemediationProposalInput = parsedInput.success
|
|
997
|
+
? parsedInput.data
|
|
998
|
+
: rawInput;
|
|
921
999
|
|
|
922
1000
|
try {
|
|
923
1001
|
const proposal = await proposeRemediationAction(db, projectId, input, {
|
|
@@ -939,7 +1017,9 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
939
1017
|
body,
|
|
940
1018
|
proposal,
|
|
941
1019
|
);
|
|
942
|
-
return
|
|
1020
|
+
return respondWithContract(
|
|
1021
|
+
c,
|
|
1022
|
+
"POST /internal/remediations/propose",
|
|
943
1023
|
{
|
|
944
1024
|
proposal,
|
|
945
1025
|
...proposal,
|
|
@@ -1002,13 +1082,17 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1002
1082
|
proposal,
|
|
1003
1083
|
storedCallback,
|
|
1004
1084
|
);
|
|
1005
|
-
return
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1085
|
+
return respondWithContract(
|
|
1086
|
+
c,
|
|
1087
|
+
"POST /internal/remediations/:id/approve",
|
|
1088
|
+
{
|
|
1089
|
+
proposal,
|
|
1090
|
+
...proposal,
|
|
1091
|
+
grantToken: proposal.grantToken ?? null,
|
|
1092
|
+
grantDelivery,
|
|
1093
|
+
...(webhookDelivery ? { webhookDelivery } : {}),
|
|
1094
|
+
},
|
|
1095
|
+
);
|
|
1012
1096
|
} catch (err) {
|
|
1013
1097
|
const message = err instanceof Error ? err.message : String(err);
|
|
1014
1098
|
const status =
|
|
@@ -1048,7 +1132,11 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1048
1132
|
reason,
|
|
1049
1133
|
},
|
|
1050
1134
|
);
|
|
1051
|
-
return
|
|
1135
|
+
return respondWithContract(
|
|
1136
|
+
c,
|
|
1137
|
+
"POST /internal/remediations/:id/reject",
|
|
1138
|
+
{ proposal, ...proposal },
|
|
1139
|
+
);
|
|
1052
1140
|
} catch (err) {
|
|
1053
1141
|
const message = err instanceof Error ? err.message : String(err);
|
|
1054
1142
|
const status =
|
|
@@ -1088,7 +1176,11 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1088
1176
|
logger: runtime.logger,
|
|
1089
1177
|
},
|
|
1090
1178
|
);
|
|
1091
|
-
return c
|
|
1179
|
+
return respondWithContract(c, "POST /internal/remediations/:id/claim", {
|
|
1180
|
+
claimed: true,
|
|
1181
|
+
proposal,
|
|
1182
|
+
...proposal,
|
|
1183
|
+
});
|
|
1092
1184
|
} catch (err) {
|
|
1093
1185
|
const message = err instanceof Error ? err.message : String(err);
|
|
1094
1186
|
const status =
|
|
@@ -1134,7 +1226,11 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1134
1226
|
: null,
|
|
1135
1227
|
},
|
|
1136
1228
|
);
|
|
1137
|
-
return
|
|
1229
|
+
return respondWithContract(
|
|
1230
|
+
c,
|
|
1231
|
+
"POST /internal/remediations/:id/complete",
|
|
1232
|
+
{ proposal, ...proposal },
|
|
1233
|
+
);
|
|
1138
1234
|
} catch (err) {
|
|
1139
1235
|
const message = err instanceof Error ? err.message : String(err);
|
|
1140
1236
|
const status =
|
|
@@ -1173,7 +1269,10 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1173
1269
|
: "Execution failed",
|
|
1174
1270
|
},
|
|
1175
1271
|
);
|
|
1176
|
-
return c
|
|
1272
|
+
return respondWithContract(c, "POST /internal/remediations/:id/fail", {
|
|
1273
|
+
proposal,
|
|
1274
|
+
...proposal,
|
|
1275
|
+
});
|
|
1177
1276
|
} catch (err) {
|
|
1178
1277
|
const message = err instanceof Error ? err.message : String(err);
|
|
1179
1278
|
const status =
|
|
@@ -1200,7 +1299,10 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1200
1299
|
: undefined,
|
|
1201
1300
|
logger: runtime.logger,
|
|
1202
1301
|
});
|
|
1203
|
-
return c
|
|
1302
|
+
return respondWithContract(c, "POST /internal/remediations/watchdog", {
|
|
1303
|
+
summary,
|
|
1304
|
+
...summary,
|
|
1305
|
+
});
|
|
1204
1306
|
});
|
|
1205
1307
|
|
|
1206
1308
|
app.get("/internal/remediations/:id", async (c) => {
|
|
@@ -1216,7 +1318,9 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1216
1318
|
if (!proposal) {
|
|
1217
1319
|
return c.json({ error: "Proposal not found" }, 404);
|
|
1218
1320
|
}
|
|
1219
|
-
return c
|
|
1321
|
+
return respondWithContract(c, "GET /internal/remediations/:id", {
|
|
1322
|
+
proposal,
|
|
1323
|
+
});
|
|
1220
1324
|
});
|
|
1221
1325
|
|
|
1222
1326
|
app.get("/internal/incidents/:id", async (c) => {
|
|
@@ -1247,7 +1351,11 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1247
1351
|
limit: 20,
|
|
1248
1352
|
}),
|
|
1249
1353
|
]);
|
|
1250
|
-
return c
|
|
1354
|
+
return respondWithContract(c, "GET /internal/incidents/:id", {
|
|
1355
|
+
incident,
|
|
1356
|
+
findings,
|
|
1357
|
+
proposals,
|
|
1358
|
+
});
|
|
1251
1359
|
});
|
|
1252
1360
|
|
|
1253
1361
|
app.get("/internal/findings/:id", async (c) => {
|
|
@@ -1263,7 +1371,7 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1263
1371
|
if (!finding) {
|
|
1264
1372
|
return c.json({ error: "Finding not found" }, 404);
|
|
1265
1373
|
}
|
|
1266
|
-
return c
|
|
1374
|
+
return respondWithContract(c, "GET /internal/findings/:id", { finding });
|
|
1267
1375
|
});
|
|
1268
1376
|
|
|
1269
1377
|
app.get("/internal/changes/:id", async (c) => {
|
|
@@ -1279,7 +1387,10 @@ export const autosreRoutesPlugin: CollectorPlugin = {
|
|
|
1279
1387
|
if (!changeEvent) {
|
|
1280
1388
|
return c.json({ error: "Change event not found" }, 404);
|
|
1281
1389
|
}
|
|
1282
|
-
return c
|
|
1390
|
+
return respondWithContract(c, "GET /internal/changes/:id", {
|
|
1391
|
+
changeEvent,
|
|
1392
|
+
change: changeEvent,
|
|
1393
|
+
});
|
|
1283
1394
|
});
|
|
1284
1395
|
},
|
|
1285
1396
|
};
|