@kici-dev/engine 0.4.0 → 0.5.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.
Files changed (41) hide show
  1. package/dist/context/host-match.js +2 -1
  2. package/dist/index.d.ts +3 -1
  3. package/dist/index.js +7 -5
  4. package/dist/labels/compile.d.ts +2 -7
  5. package/dist/labels/compile.js +1 -10
  6. package/dist/labels.d.ts +8 -0
  7. package/dist/labels.js +9 -1
  8. package/dist/metrics/catalog-policy.d.ts +11 -0
  9. package/dist/metrics/catalog-policy.js +13 -3
  10. package/dist/metrics/metric-catalog.generated.d.ts +30 -0
  11. package/dist/metrics/metric-catalog.generated.js +36 -0
  12. package/dist/protocol/messages/dashboard-global-workflows.d.ts +8 -3
  13. package/dist/protocol/messages/dashboard-global-workflows.js +20 -3
  14. package/dist/protocol/messages/dashboard.d.ts +5 -2
  15. package/dist/protocol/messages/dashboard.js +7 -0
  16. package/dist/protocol/messages/execution-status.d.ts +3 -0
  17. package/dist/protocol/messages/execution-status.js +16 -0
  18. package/dist/protocol/messages/orchestrator-agent.d.ts +49 -0
  19. package/dist/protocol/messages/orchestrator-agent.js +34 -1
  20. package/dist/protocol/messages/platform-orchestrator.d.ts +5 -2
  21. package/dist/protocol/messages/platform-orchestrator.js +14 -0
  22. package/dist/provider/check-status-poster.d.ts +14 -0
  23. package/dist/provider/file-contents-fetcher.d.ts +39 -0
  24. package/dist/provider/file-contents-fetcher.js +2 -0
  25. package/dist/provider/index.d.ts +2 -0
  26. package/dist/safe-regex.d.ts +16 -0
  27. package/dist/safe-regex.js +24 -0
  28. package/dist/trigger/compiled-matchers.d.ts +21 -1
  29. package/dist/trigger/compiled-matchers.js +30 -3
  30. package/dist/trigger/content-requirements.d.ts +31 -0
  31. package/dist/trigger/content-requirements.js +125 -0
  32. package/dist/trigger/decision-trace.d.ts +89 -0
  33. package/dist/trigger/decision-trace.js +96 -1
  34. package/dist/trigger/jsonpath-matcher.js +5 -1
  35. package/dist/trigger/matcher.js +57 -8
  36. package/dist/trigger/text-match.d.ts +27 -0
  37. package/dist/trigger/text-match.js +86 -0
  38. package/dist/trigger/types.d.ts +179 -17
  39. package/dist/trigger/types.js +32 -5
  40. package/package.json +10 -1
  41. package/sbom.spdx.json +30 -5
@@ -299,6 +299,7 @@ export declare const dashboardRunStateResponseSchema: z.ZodObject<{
299
299
  }>;
300
300
  routingKey: z.ZodOptional<z.ZodString>;
301
301
  repoIdentifier: z.ZodOptional<z.ZodString>;
302
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
302
303
  sha: z.ZodOptional<z.ZodString>;
303
304
  ref: z.ZodOptional<z.ZodString>;
304
305
  triggerEvent: z.ZodOptional<z.ZodString>;
@@ -6616,7 +6617,6 @@ export declare const dashboardPlatformToOrchSchema: z.ZodDiscriminatedUnion<[z.Z
6616
6617
  type: z.ZodLiteral<"system">;
6617
6618
  component: z.ZodString;
6618
6619
  }, z.core.$strip>], "type">;
6619
- enabled: z.ZodOptional<z.ZodBoolean>;
6620
6620
  allowedRepos: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
6621
6621
  routingKey: z.ZodOptional<z.ZodString>;
6622
6622
  pattern: z.ZodString;
@@ -6629,7 +6629,7 @@ export declare const dashboardPlatformToOrchSchema: z.ZodDiscriminatedUnion<[z.Z
6629
6629
  routingKey: z.ZodOptional<z.ZodString>;
6630
6630
  pattern: z.ZodString;
6631
6631
  }, z.core.$strip>>>>;
6632
- }, z.core.$strip>, z.ZodObject<{
6632
+ }, z.core.$strict>, z.ZodObject<{
6633
6633
  type: z.ZodLiteral<"dashboard.access-log.list">;
6634
6634
  requestId: z.ZodString;
6635
6635
  actor: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -7296,6 +7296,7 @@ export declare const dashboardOrchToPlatformSchema: z.ZodDiscriminatedUnion<[z.Z
7296
7296
  }>;
7297
7297
  routingKey: z.ZodOptional<z.ZodString>;
7298
7298
  repoIdentifier: z.ZodOptional<z.ZodString>;
7299
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
7299
7300
  sha: z.ZodOptional<z.ZodString>;
7300
7301
  ref: z.ZodOptional<z.ZodString>;
7301
7302
  triggerEvent: z.ZodOptional<z.ZodString>;
@@ -8821,6 +8822,7 @@ export declare const runListItemSchema: z.ZodObject<{
8821
8822
  workflowName: z.ZodString;
8822
8823
  status: z.ZodString;
8823
8824
  repoIdentifier: z.ZodNullable<z.ZodString>;
8825
+ workflowRepoIdentifier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
8824
8826
  sha: z.ZodNullable<z.ZodString>;
8825
8827
  ref: z.ZodNullable<z.ZodString>;
8826
8828
  triggerEvent: z.ZodNullable<z.ZodString>;
@@ -8878,6 +8880,7 @@ export declare const runListResponseSchema: z.ZodObject<{
8878
8880
  workflowName: z.ZodString;
8879
8881
  status: z.ZodString;
8880
8882
  repoIdentifier: z.ZodNullable<z.ZodString>;
8883
+ workflowRepoIdentifier: z.ZodOptional<z.ZodNullable<z.ZodString>>;
8881
8884
  sha: z.ZodNullable<z.ZodString>;
8882
8885
  ref: z.ZodNullable<z.ZodString>;
8883
8886
  triggerEvent: z.ZodNullable<z.ZodString>;
@@ -2203,6 +2203,13 @@ const runListItemSchema = z.object({
2203
2203
  workflowName: z.string(),
2204
2204
  status: z.string(),
2205
2205
  repoIdentifier: z.string().nullable(),
2206
+ /**
2207
+ * The repository that DEFINES this run's workflow. Non-null only when it
2208
+ * differs from `repoIdentifier` — i.e. this is an organization-wide global
2209
+ * run, whose workflow file lives in another repo entirely. Optional so a
2210
+ * client parsing a response from an older Platform still validates.
2211
+ */
2212
+ workflowRepoIdentifier: z.string().nullable().optional(),
2206
2213
  sha: z.string().nullable(),
2207
2214
  ref: z.string().nullable(),
2208
2215
  triggerEvent: z.string().nullable(),
@@ -264,6 +264,7 @@ export declare const executionStatusSchema: z.ZodObject<{
264
264
  }>;
265
265
  routingKey: z.ZodOptional<z.ZodString>;
266
266
  repoIdentifier: z.ZodOptional<z.ZodString>;
267
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
267
268
  repoProvider: z.ZodOptional<z.ZodString>;
268
269
  localWorkingTree: z.ZodOptional<z.ZodBoolean>;
269
270
  sha: z.ZodOptional<z.ZodString>;
@@ -417,6 +418,7 @@ export declare const stateReplayRunSchema: z.ZodObject<{
417
418
  }>;
418
419
  routingKey: z.ZodOptional<z.ZodString>;
419
420
  repoIdentifier: z.ZodOptional<z.ZodString>;
421
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
420
422
  sha: z.ZodOptional<z.ZodString>;
421
423
  ref: z.ZodOptional<z.ZodString>;
422
424
  triggerEvent: z.ZodOptional<z.ZodString>;
@@ -468,6 +470,7 @@ export declare const stateReplaySchema: z.ZodObject<{
468
470
  }>;
469
471
  routingKey: z.ZodOptional<z.ZodString>;
470
472
  repoIdentifier: z.ZodOptional<z.ZodString>;
473
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
471
474
  sha: z.ZodOptional<z.ZodString>;
472
475
  ref: z.ZodOptional<z.ZodString>;
473
476
  triggerEvent: z.ZodOptional<z.ZodString>;
@@ -239,6 +239,15 @@ const executionStatusSchema = z.object({
239
239
  routingKey: z.string().max(128).optional(),
240
240
  repoIdentifier: z.string().max(256).optional(),
241
241
  /**
242
+ * The repository that DEFINES the workflow, when that is not
243
+ * `repoIdentifier` — a global workflow authored in one repository and
244
+ * dispatched against another. Absent for every per-repository run, where the
245
+ * two are the same repository, so "present" is a precise marker for a
246
+ * cross-repository global run. Optional for backward compatibility with an
247
+ * older orchestrator that never sends it.
248
+ */
249
+ workflowRepoIdentifier: z.string().max(256).optional(),
250
+ /**
242
251
  * Run-level repo provider (origin host: `github` / `gitlab` / `bitbucket` /
243
252
  * `local`). Distinct from the routing-key-derived source provider; drives the
244
253
  * dashboard's provider-aware repo links.
@@ -359,6 +368,13 @@ const stateReplayRunSchema = z.object({
359
368
  status: ExecutionRunStatus,
360
369
  routingKey: z.string().max(128).optional(),
361
370
  repoIdentifier: z.string().max(256).optional(),
371
+ /**
372
+ * The repository that DEFINES the workflow, when that is not
373
+ * `repoIdentifier`. Same meaning and same absent-for-per-repository-runs
374
+ * contract as on `execution.status`; carried here so a run that reaches the
375
+ * Platform only through the reconnect replay keeps its attribution.
376
+ */
377
+ workflowRepoIdentifier: z.string().max(256).optional(),
362
378
  sha: z.string().max(128).optional(),
363
379
  ref: z.string().max(128).optional(),
364
380
  triggerEvent: z.string().max(128).optional(),
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import type { LockJob } from '../../trigger/types.js';
2
3
  /**
3
4
  * Cache write scope for a job's user-facing cache.
4
5
  *
@@ -232,6 +233,54 @@ export declare const jobStatusSchema: z.ZodObject<{
232
233
  encrypted: z.ZodString;
233
234
  }, z.core.$strip>>>;
234
235
  }, z.core.$strip>;
236
+ /**
237
+ * One candidate workflow's verdict from the pre-run global eval round — the
238
+ * job the agent runs once per (event × workflow repo) before any run row
239
+ * exists, evaluating each candidate's `filter` and then its `DynamicJobFn`s on
240
+ * a single dual checkout.
241
+ *
242
+ * `jobs` carries `LockJob[]` as an unvalidated pass-through, the same shape and
243
+ * for the same reason as `jobDispatchSchema.jobConfig`: the lock-file job shape
244
+ * has no Zod mirror anywhere in this package, its single source of truth is the
245
+ * `LockJob` interface in `trigger/types.ts`, and a hand-written Zod copy would
246
+ * drift and start rejecting legitimate generated jobs.
247
+ *
248
+ * Every field beyond the verdict itself is `.optional()` so an older peer
249
+ * tolerates the message unchanged.
250
+ */
251
+ export declare const globalEvalCandidateResultSchema: z.ZodObject<{
252
+ workflowName: z.ZodString;
253
+ run: z.ZodBoolean;
254
+ jobs: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
255
+ indeterminate: z.ZodOptional<z.ZodBoolean>;
256
+ reason: z.ZodOptional<z.ZodString>;
257
+ }, z.core.$strip>;
258
+ /** Every candidate's verdict from one global eval round, in candidate order. */
259
+ export declare const globalEvalRoundResultSchema: z.ZodObject<{
260
+ candidates: z.ZodArray<z.ZodObject<{
261
+ workflowName: z.ZodString;
262
+ run: z.ZodBoolean;
263
+ jobs: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
264
+ indeterminate: z.ZodOptional<z.ZodBoolean>;
265
+ reason: z.ZodOptional<z.ZodString>;
266
+ }, z.core.$strip>>;
267
+ }, z.core.$strip>;
268
+ /**
269
+ * Typed view of {@link globalEvalCandidateResultSchema}. Declared rather than
270
+ * inferred so `jobs` is the real `LockJob[]` on both sides of the wire; the Zod
271
+ * schema stays the loose validator (see its doc comment).
272
+ */
273
+ export interface GlobalEvalCandidateResult {
274
+ workflowName: string;
275
+ run: boolean;
276
+ jobs?: LockJob[];
277
+ indeterminate?: boolean;
278
+ reason?: string;
279
+ }
280
+ /** Typed view of {@link globalEvalRoundResultSchema}. */
281
+ export interface GlobalEvalRoundResult {
282
+ candidates: GlobalEvalCandidateResult[];
283
+ }
235
284
  /** Reasons an agent can refuse a job.dispatch. */
236
285
  export declare const JobRejectReason: z.ZodEnum<{
237
286
  busy: "busy";
@@ -288,6 +288,39 @@ const jobStatusSchema = z.object({
288
288
  encrypted: z.string()
289
289
  })).optional()
290
290
  });
291
+ /**
292
+ * One candidate workflow's verdict from the pre-run global eval round — the
293
+ * job the agent runs once per (event × workflow repo) before any run row
294
+ * exists, evaluating each candidate's `filter` and then its `DynamicJobFn`s on
295
+ * a single dual checkout.
296
+ *
297
+ * `jobs` carries `LockJob[]` as an unvalidated pass-through, the same shape and
298
+ * for the same reason as `jobDispatchSchema.jobConfig`: the lock-file job shape
299
+ * has no Zod mirror anywhere in this package, its single source of truth is the
300
+ * `LockJob` interface in `trigger/types.ts`, and a hand-written Zod copy would
301
+ * drift and start rejecting legitimate generated jobs.
302
+ *
303
+ * Every field beyond the verdict itself is `.optional()` so an older peer
304
+ * tolerates the message unchanged.
305
+ */
306
+ const globalEvalCandidateResultSchema = z.object({
307
+ /** The candidate workflow's name, as it appears in the lock file. */
308
+ workflowName: z.string(),
309
+ /** Whether this workflow applies to the source repo that triggered the round. */
310
+ run: z.boolean(),
311
+ jobs: z.array(z.record(z.string(), z.unknown())).optional().describe("Jobs generated by the workflow DynamicJobFns (LockJob[])"),
312
+ /**
313
+ * Set when the verdict could not be established — the filter or a generator
314
+ * threw, or blew the per-candidate budget. `run` is `false` alongside it, but
315
+ * that is a "could not decide", not a clean "does not apply": one bad
316
+ * candidate never fails the round, so its siblings still carry real verdicts.
317
+ */
318
+ indeterminate: z.boolean().optional(),
319
+ /** Human-readable cause, present when `indeterminate` is set. */
320
+ reason: z.string().optional()
321
+ });
322
+ /** Every candidate's verdict from one global eval round, in candidate order. */
323
+ const globalEvalRoundResultSchema = z.object({ candidates: z.array(globalEvalCandidateResultSchema) });
291
324
  /** Reasons an agent can refuse a job.dispatch. */
292
325
  const JobRejectReason = z.enum(["busy", "draining"]);
293
326
  /**
@@ -945,6 +978,6 @@ const agentToOrchestratorMessageSchema = z.discriminatedUnion("type", [
945
978
  stepApprovalRequestSchema
946
979
  ]);
947
980
  //#endregion
948
- export { ArtifactCompleteAckOutcome, ArtifactDownloadOutcome, ArtifactRejectReason, ArtifactUploadOutcome, CacheRefScope, JobRejectReason, StepApprovalOutcome, agentApiRequestSchema, agentApiResponseSchema, agentAuthFailureSchema, agentAuthRequestSchema, agentAuthSuccessSchema, agentLogChunkSchema, agentMetricsSchema, agentRegisterSchema, agentStatusSchema, agentStepStatusSchema, agentToOrchestratorMessageSchema, artifactsDownloadRequestSchema, artifactsDownloadResponseSchema, artifactsUploadCompleteAckSchema, artifactsUploadCompleteSchema, artifactsUploadRequestSchema, artifactsUploadResponseSchema, cacheUserRestoreRequestSchema, cacheUserRestoreResponseSchema, cacheUserSaveCompleteSchema, cacheUserSaveRequestSchema, cacheUserSaveResponseSchema, configAckSchema, eventEmitResponseSchema, eventEmitSchema, fleetBundleChunkSchema, fleetBundleErrorSchema, fleetLogsRequestSchema, gitAuthSchema, jobAckSchema, jobCancelSchema, jobConcurrencyAckSchema, jobConcurrencyReportSchema, jobDispatchSchema, jobRejectSchema, jobStatusSchema, orchestratorToAgentMessageSchema, provenanceUploadCompleteSchema, provenanceUploadDeferSchema, provenanceUploadRequestSchema, provenanceUploadResponseSchema, registerAckSchema, stepApprovalPayloadSchema, stepApprovalRequestSchema, stepApprovalResolvedSchema, upstreamSnapshotSchema };
981
+ export { ArtifactCompleteAckOutcome, ArtifactDownloadOutcome, ArtifactRejectReason, ArtifactUploadOutcome, CacheRefScope, JobRejectReason, StepApprovalOutcome, agentApiRequestSchema, agentApiResponseSchema, agentAuthFailureSchema, agentAuthRequestSchema, agentAuthSuccessSchema, agentLogChunkSchema, agentMetricsSchema, agentRegisterSchema, agentStatusSchema, agentStepStatusSchema, agentToOrchestratorMessageSchema, artifactsDownloadRequestSchema, artifactsDownloadResponseSchema, artifactsUploadCompleteAckSchema, artifactsUploadCompleteSchema, artifactsUploadRequestSchema, artifactsUploadResponseSchema, cacheUserRestoreRequestSchema, cacheUserRestoreResponseSchema, cacheUserSaveCompleteSchema, cacheUserSaveRequestSchema, cacheUserSaveResponseSchema, configAckSchema, eventEmitResponseSchema, eventEmitSchema, fleetBundleChunkSchema, fleetBundleErrorSchema, fleetLogsRequestSchema, gitAuthSchema, globalEvalCandidateResultSchema, globalEvalRoundResultSchema, jobAckSchema, jobCancelSchema, jobConcurrencyAckSchema, jobConcurrencyReportSchema, jobDispatchSchema, jobRejectSchema, jobStatusSchema, orchestratorToAgentMessageSchema, provenanceUploadCompleteSchema, provenanceUploadDeferSchema, provenanceUploadRequestSchema, provenanceUploadResponseSchema, registerAckSchema, stepApprovalPayloadSchema, stepApprovalRequestSchema, stepApprovalResolvedSchema, upstreamSnapshotSchema };
949
982
 
950
983
  //# sourceMappingURL=orchestrator-agent.js.map
@@ -215,6 +215,7 @@ export declare const staleCheckrunCleanupSchema: z.ZodObject<{
215
215
  repoIdentifier: z.ZodString;
216
216
  sha: z.ZodString;
217
217
  workflowName: z.ZodString;
218
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
218
219
  jobNames: z.ZodArray<z.ZodString>;
219
220
  }, z.core.$strip>>;
220
221
  }, z.core.$strip>;
@@ -562,6 +563,7 @@ export declare const platformToOrchestratorMessageSchema: z.ZodDiscriminatedUnio
562
563
  repoIdentifier: z.ZodString;
563
564
  sha: z.ZodString;
564
565
  workflowName: z.ZodString;
566
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
565
567
  jobNames: z.ZodArray<z.ZodString>;
566
568
  }, z.core.$strip>>;
567
569
  }, z.core.$strip>, z.ZodObject<{
@@ -2762,7 +2764,6 @@ export declare const platformToOrchestratorMessageSchema: z.ZodDiscriminatedUnio
2762
2764
  type: z.ZodLiteral<"system">;
2763
2765
  component: z.ZodString;
2764
2766
  }, z.core.$strip>], "type">;
2765
- enabled: z.ZodOptional<z.ZodBoolean>;
2766
2767
  allowedRepos: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
2767
2768
  routingKey: z.ZodOptional<z.ZodString>;
2768
2769
  pattern: z.ZodString;
@@ -2775,7 +2776,7 @@ export declare const platformToOrchestratorMessageSchema: z.ZodDiscriminatedUnio
2775
2776
  routingKey: z.ZodOptional<z.ZodString>;
2776
2777
  pattern: z.ZodString;
2777
2778
  }, z.core.$strip>>>>;
2778
- }, z.core.$strip>, z.ZodObject<{
2779
+ }, z.core.$strict>, z.ZodObject<{
2779
2780
  type: z.ZodLiteral<"dashboard.access-log.list">;
2780
2781
  requestId: z.ZodString;
2781
2782
  actor: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -3207,6 +3208,7 @@ export declare const orchestratorToPlatformMessageSchema: z.ZodDiscriminatedUnio
3207
3208
  }>;
3208
3209
  routingKey: z.ZodOptional<z.ZodString>;
3209
3210
  repoIdentifier: z.ZodOptional<z.ZodString>;
3211
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
3210
3212
  repoProvider: z.ZodOptional<z.ZodString>;
3211
3213
  localWorkingTree: z.ZodOptional<z.ZodBoolean>;
3212
3214
  sha: z.ZodOptional<z.ZodString>;
@@ -3349,6 +3351,7 @@ export declare const orchestratorToPlatformMessageSchema: z.ZodDiscriminatedUnio
3349
3351
  }>;
3350
3352
  routingKey: z.ZodOptional<z.ZodString>;
3351
3353
  repoIdentifier: z.ZodOptional<z.ZodString>;
3354
+ workflowRepoIdentifier: z.ZodOptional<z.ZodString>;
3352
3355
  sha: z.ZodOptional<z.ZodString>;
3353
3356
  ref: z.ZodOptional<z.ZodString>;
3354
3357
  triggerEvent: z.ZodOptional<z.ZodString>;
@@ -239,6 +239,20 @@ const staleCheckrunCleanupSchema = z.object({
239
239
  repoIdentifier: z.string(),
240
240
  sha: z.string(),
241
241
  workflowName: z.string(),
242
+ /**
243
+ * The repository that DEFINES the workflow, when that is not the
244
+ * repository the run acted on — an organization-wide workflow dispatched
245
+ * against another repository. The orchestrator qualifies the check-run
246
+ * names it looks for with it, so a cleanup cannot time out the acted-on
247
+ * repository's own same-named check; see the orchestrator's
248
+ * `workflowLabel`.
249
+ *
250
+ * Additive and optional. The Platform sends it on exactly the condition
251
+ * that writes the mirror column — only when the two repositories differ —
252
+ * so an absent field and a value equal to `repoIdentifier` mean the same
253
+ * thing and both name the unqualified check.
254
+ */
255
+ workflowRepoIdentifier: z.string().max(256).optional(),
242
256
  jobNames: z.array(z.string())
243
257
  }))
244
258
  });
@@ -34,5 +34,19 @@ export interface CheckStatusPoster {
34
34
  * unblocking a branch protection rule that requires the security check.
35
35
  */
36
36
  postGlobalWorkflowsSkippedCheck(repoIdentifier: string, commitSha: string, summary: string, credentials: unknown): Promise<void>;
37
+ /**
38
+ * Post a failing check recording that the pre-run evaluation of the
39
+ * organization's global workflows could not be completed, so none of the
40
+ * workflows it was deciding on ran for this commit.
41
+ *
42
+ * Its own check name, for the same reason as the two notices above: the
43
+ * security-hold check is a single named run per commit, so posting this
44
+ * through `postCheckStatus` would UPDATE that run and replace a pending
45
+ * "Held for approval" state with a completed conclusion.
46
+ *
47
+ * Optional so a provider bundle that has no notion of commit checks — or a
48
+ * hand-built one — is simply silent rather than failing the delivery.
49
+ */
50
+ postGlobalEvalFailedCheck?(repoIdentifier: string, commitSha: string, summary: string, credentials: unknown): Promise<void>;
37
51
  }
38
52
  //# sourceMappingURL=check-status-poster.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * FileContentsFetcher interface.
3
+ *
4
+ * Fetches the contents of an arbitrary repository file at a specific ref via a
5
+ * provider's repository API. Used by the orchestrator to evaluate content-match
6
+ * triggers without cloning the repo.
7
+ */
8
+ import type { ProviderType } from './types.js';
9
+ export interface FileContentsFetcher {
10
+ readonly provider: ProviderType;
11
+ /**
12
+ * Fetch the contents of a file in a repository at a specific ref.
13
+ *
14
+ * Result shape:
15
+ * - `{ present: false }` -- the file does not exist (a 404 from the provider,
16
+ * or the path resolves to a directory rather than a file).
17
+ * - `{ present: true, bytes }` -- the file exists and the provider returned
18
+ * its inline content, decoded to a string.
19
+ * - `{ present: true }` (no `bytes`) -- the file exists but the provider did
20
+ * not return inline content (e.g. GitHub's Contents API omits content for
21
+ * files larger than 1 MiB). A caller MUST NOT read a missing `bytes` as an
22
+ * absent file.
23
+ *
24
+ * Implementations do not cap the returned content -- any size limit is the
25
+ * caller's concern (the orchestrator's content matcher enforces a
26
+ * post-materialization cap). Implementations MUST NOT fall back to a raw
27
+ * blob download to defeat a provider's inline-content size limit.
28
+ *
29
+ * @param owner - Repository owner (e.g. "my-org")
30
+ * @param repo - Repository name (e.g. "my-app")
31
+ * @param path - Repo-relative file path (e.g. ".kici/workflows/ci.ts")
32
+ * @param ref - Git ref (branch name, tag, or SHA)
33
+ */
34
+ getFileContents(owner: string, repo: string, path: string, ref: string): Promise<{
35
+ present: boolean;
36
+ bytes?: string;
37
+ }>;
38
+ }
39
+ //# sourceMappingURL=file-contents-fetcher.d.ts.map
@@ -0,0 +1,2 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ export {};
@@ -8,6 +8,7 @@
8
8
  * - WebhookNormalizer: Webhook ingestion and event normalization
9
9
  * - LockFileFetcher: Repository API access for lock files
10
10
  * - ChangedFilesFetcher: Repository API access for changed files
11
+ * - FileContentsFetcher: Repository API access for arbitrary file contents
11
12
  * - CloneTokenProvider: Auth token generation for agent clone
12
13
  * - RepoUrlBuilder: Provider-specific URL construction
13
14
  */
@@ -16,6 +17,7 @@ export type { WebhookNormalizer, AccessCacheInvalidation } from './webhook-norma
16
17
  export type { LockFileFetcher } from './lock-file-fetcher.js';
17
18
  export { LockFileParseError } from './lock-file-parse-error.js';
18
19
  export type { ChangedFilesFetcher, ChangedFilesResult } from './changed-files-fetcher.js';
20
+ export type { FileContentsFetcher } from './file-contents-fetcher.js';
19
21
  export type { CloneTokenProvider, ProviderGitAuth } from './clone-token-provider.js';
20
22
  export type { RepoUrlBuilder } from './repo-url-builder.js';
21
23
  export type { ContributorResolver, ContributorInfo, ContributorPermission, } from './contributor-resolver.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Reject a ReDoS-prone author-supplied regex before it is compiled.
3
+ *
4
+ * `safe-regex` is a star-height heuristic. The orchestrator is single-tenant, so
5
+ * a slipped-through pattern only stalls the author's own orchestrator — but every
6
+ * author regex the orchestrator compiles from lock-file data on the webhook path
7
+ * (label selectors, branch/tag/repo patterns, embedded JSONPath `/re/flags`,
8
+ * comment `bodyMatch`) must be checked so a catastrophic pattern is rejected at
9
+ * compile/registration time rather than silently compiled. Globs are linear by
10
+ * construction but pass through here for uniformity.
11
+ *
12
+ * `ctx` is a human label (e.g. "branch pattern", "job 'web' runsOn") woven into
13
+ * the thrown error so an operator can identify the offending pattern.
14
+ */
15
+ export declare function assertSafeRegex(source: string, flags: string, ctx: string): void;
16
+ //# sourceMappingURL=safe-regex.d.ts.map
@@ -0,0 +1,24 @@
1
+ import "./rolldown-runtime-ClRpJifh.js";
2
+ import safeRegex from "safe-regex";
3
+ //#region src/safe-regex.ts
4
+ /**
5
+ * Reject a ReDoS-prone author-supplied regex before it is compiled.
6
+ *
7
+ * `safe-regex` is a star-height heuristic. The orchestrator is single-tenant, so
8
+ * a slipped-through pattern only stalls the author's own orchestrator — but every
9
+ * author regex the orchestrator compiles from lock-file data on the webhook path
10
+ * (label selectors, branch/tag/repo patterns, embedded JSONPath `/re/flags`,
11
+ * comment `bodyMatch`) must be checked so a catastrophic pattern is rejected at
12
+ * compile/registration time rather than silently compiled. Globs are linear by
13
+ * construction but pass through here for uniformity.
14
+ *
15
+ * `ctx` is a human label (e.g. "branch pattern", "job 'web' runsOn") woven into
16
+ * the thrown error so an operator can identify the offending pattern.
17
+ */
18
+ function assertSafeRegex(source, flags, ctx) {
19
+ if (!safeRegex(new RegExp(source, flags))) throw new Error(`${ctx}: regex /${source}/${flags} is ReDoS-prone — rejected`);
20
+ }
21
+ //#endregion
22
+ export { assertSafeRegex };
23
+
24
+ //# sourceMappingURL=safe-regex.js.map
@@ -3,11 +3,31 @@
3
3
  * flags first with a space separator; regex flags are restricted to
4
4
  * `[gimsuydv]`, so the separator can never collide with a pattern that starts
5
5
  * with a space.
6
+ *
7
+ * Every pattern reaching here is author-supplied (branch/tag/repo patterns and
8
+ * comment `bodyMatch`), so it is ReDoS-checked before compiling. The guard runs
9
+ * inside the memo factory, so a benign pattern pays the check once (on cache
10
+ * miss) and a catastrophic one throws — and, being unsafe, is never cached, so
11
+ * it is rejected on every attempt. `ctx` names the dialect in the thrown error.
6
12
  */
7
- export declare function getCompiledRegex(pattern: string, flags?: string): RegExp;
13
+ export declare function getCompiledRegex(pattern: string, flags?: string, ctx?: string): RegExp;
8
14
  /**
9
15
  * Return a memoized picomatch matcher function for the given glob pattern.
10
16
  * `getGlobMatcher(pattern)(str)` is equivalent to `picomatch.isMatch(str, pattern)`.
11
17
  */
12
18
  export declare function getGlobMatcher(pattern: string): (s: string) => boolean;
19
+ /**
20
+ * Repo-identifier matcher. Identical to {@link getGlobMatcher} except it sets
21
+ * picomatch's `dot: true`, so a dot-prefixed identifier (`.hidden/repo`) is
22
+ * matched by `**` — `repos: ['**']` is documented as "every repo in the org",
23
+ * and silently excluding a whole class of identifier contradicts that.
24
+ *
25
+ * Deliberately NOT the shared matcher: `dot: true` on path globs would make
26
+ * `paths: ['**']` start matching `.github/**` for every existing workflow, a
27
+ * semantics change this does not intend.
28
+ *
29
+ * Note a bare `.` still does not match, in either mode — picomatch will not
30
+ * match a lone `.`. That is upstream behavior, not something this option fixes.
31
+ */
32
+ export declare function getRepoGlobMatcher(pattern: string): (s: string) => boolean;
13
33
  //# sourceMappingURL=compiled-matchers.d.ts.map
@@ -1,4 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
+ import { assertSafeRegex } from "../safe-regex.js";
2
3
  import picomatch from "picomatch";
3
4
  //#region src/trigger/compiled-matchers.ts
4
5
  /**
@@ -22,14 +23,24 @@ function boundedGet(cache, key, make) {
22
23
  }
23
24
  const regexCache = /* @__PURE__ */ new Map();
24
25
  const globCache = /* @__PURE__ */ new Map();
26
+ const repoGlobCache = /* @__PURE__ */ new Map();
25
27
  /**
26
28
  * Return a memoized RegExp for the given pattern + flags. The key encodes the
27
29
  * flags first with a space separator; regex flags are restricted to
28
30
  * `[gimsuydv]`, so the separator can never collide with a pattern that starts
29
31
  * with a space.
32
+ *
33
+ * Every pattern reaching here is author-supplied (branch/tag/repo patterns and
34
+ * comment `bodyMatch`), so it is ReDoS-checked before compiling. The guard runs
35
+ * inside the memo factory, so a benign pattern pays the check once (on cache
36
+ * miss) and a catastrophic one throws — and, being unsafe, is never cached, so
37
+ * it is rejected on every attempt. `ctx` names the dialect in the thrown error.
30
38
  */
31
- function getCompiledRegex(pattern, flags) {
32
- return boundedGet(regexCache, `${flags ?? ""} ${pattern}`, () => new RegExp(pattern, flags));
39
+ function getCompiledRegex(pattern, flags, ctx = "trigger pattern") {
40
+ return boundedGet(regexCache, `${flags ?? ""} ${pattern}`, () => {
41
+ assertSafeRegex(pattern, flags ?? "", ctx);
42
+ return new RegExp(pattern, flags);
43
+ });
33
44
  }
34
45
  /**
35
46
  * Return a memoized picomatch matcher function for the given glob pattern.
@@ -38,7 +49,23 @@ function getCompiledRegex(pattern, flags) {
38
49
  function getGlobMatcher(pattern) {
39
50
  return boundedGet(globCache, pattern, () => picomatch(pattern));
40
51
  }
52
+ /**
53
+ * Repo-identifier matcher. Identical to {@link getGlobMatcher} except it sets
54
+ * picomatch's `dot: true`, so a dot-prefixed identifier (`.hidden/repo`) is
55
+ * matched by `**` — `repos: ['**']` is documented as "every repo in the org",
56
+ * and silently excluding a whole class of identifier contradicts that.
57
+ *
58
+ * Deliberately NOT the shared matcher: `dot: true` on path globs would make
59
+ * `paths: ['**']` start matching `.github/**` for every existing workflow, a
60
+ * semantics change this does not intend.
61
+ *
62
+ * Note a bare `.` still does not match, in either mode — picomatch will not
63
+ * match a lone `.`. That is upstream behavior, not something this option fixes.
64
+ */
65
+ function getRepoGlobMatcher(pattern) {
66
+ return boundedGet(repoGlobCache, pattern, () => picomatch(pattern, { dot: true }));
67
+ }
41
68
  //#endregion
42
- export { getCompiledRegex, getGlobMatcher };
69
+ export { getCompiledRegex, getGlobMatcher, getRepoGlobMatcher };
43
70
 
44
71
  //# sourceMappingURL=compiled-matchers.js.map
@@ -0,0 +1,31 @@
1
+ import type { LockContentRequirement } from './types.js';
2
+ export type { ContentFormat, ContentRequirement, LockContentRequirement } from './types.js';
3
+ /** Result of evaluating a `requires` list: a definite verdict, or fail-visible indeterminate. */
4
+ export interface ContentRequirementResult {
5
+ readonly pass: boolean;
6
+ /** Set (with `pass:false`) when a file could not be evaluated — never a silent pass. */
7
+ readonly indeterminate?: string;
8
+ }
9
+ /**
10
+ * Parse `bytes` for the given concrete format. `text` returns the raw string;
11
+ * `json` uses `JSON.parse`; `yaml` uses a hardened `yaml.parse` with an explicit
12
+ * anchor/alias cap. Throws on a malformed document (the caller treats a throw as
13
+ * indeterminate).
14
+ */
15
+ export declare function parseForFormat(bytes: string, format: 'json' | 'yaml' | 'text'): unknown;
16
+ /**
17
+ * Evaluate an AND-ed list of content requirements against a resolved file map.
18
+ *
19
+ * Every entry must pass for the overall result to pass; an empty list passes.
20
+ * The first indeterminate entry short-circuits and is surfaced (fail-visible):
21
+ * an unevaluable file NEVER passes silently.
22
+ *
23
+ * @param reqs The lock `requires` list (each entry AND-ed).
24
+ * @param files Resolved file contents keyed by repo-relative path. A missing key
25
+ * or `{ present: false }` means the file does not exist at the ref.
26
+ */
27
+ export declare function evaluateContentRequirements(reqs: readonly LockContentRequirement[], files: Map<string, {
28
+ present: boolean;
29
+ bytes?: string;
30
+ }>): ContentRequirementResult;
31
+ //# sourceMappingURL=content-requirements.d.ts.map