@kici-dev/engine 0.1.25 → 0.1.27

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 (48) hide show
  1. package/dist/approval/types.d.ts +3 -3
  2. package/dist/approval/types.js +3 -3
  3. package/dist/audit/access-log-policy.js +12 -11
  4. package/dist/audit/retention-policy.js +24 -22
  5. package/dist/context/host-match.d.ts +25 -0
  6. package/dist/{environment → context}/host-match.js +1 -1
  7. package/dist/context/index.d.ts +6 -0
  8. package/dist/context/index.js +5 -0
  9. package/dist/context/multi-context.d.ts +30 -0
  10. package/dist/context/multi-context.js +38 -0
  11. package/dist/context/scope-resolver.d.ts +46 -0
  12. package/dist/{environment → context}/scope-resolver.js +6 -6
  13. package/dist/context/scope-template.d.ts +18 -0
  14. package/dist/{environment → context}/scope-template.js +1 -1
  15. package/dist/context/types.d.ts +119 -0
  16. package/dist/{environment → context}/types.js +3 -3
  17. package/dist/dev-ops/operations.d.ts +1 -1
  18. package/dist/dev-ops/operations.js +1 -1
  19. package/dist/env/environment-allowlist.d.ts +23 -0
  20. package/dist/env/environment-allowlist.js +35 -1
  21. package/dist/fanout/materialize.js +2 -2
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +8 -8
  24. package/dist/metrics/metric-catalog.generated.d.ts +15 -10
  25. package/dist/metrics/metric-catalog.generated.js +18 -12
  26. package/dist/protocol/dashboard-api-errors.d.ts +12 -0
  27. package/dist/protocol/dashboard-api-errors.js +13 -0
  28. package/dist/protocol/dashboard-write-operations.d.ts +22 -22
  29. package/dist/protocol/dashboard-write-operations.js +52 -52
  30. package/dist/protocol/messages/access-log.d.ts +65 -60
  31. package/dist/protocol/messages/access-log.js +13 -12
  32. package/dist/protocol/messages/agent-run-result.d.ts +2 -2
  33. package/dist/protocol/messages/agent-run-result.js +1 -1
  34. package/dist/protocol/messages/auth.d.ts +7 -7
  35. package/dist/protocol/messages/capabilities.d.ts +7 -7
  36. package/dist/protocol/messages/dashboard.d.ts +235 -233
  37. package/dist/protocol/messages/dashboard.js +191 -191
  38. package/dist/protocol/messages/execution-status.d.ts +9 -9
  39. package/dist/protocol/messages/execution-status.js +8 -8
  40. package/dist/protocol/messages/platform-orchestrator.d.ts +75 -74
  41. package/dist/protocol/session-policy.d.ts +20 -0
  42. package/dist/protocol/session-policy.js +25 -0
  43. package/dist/trigger/types.d.ts +7 -6
  44. package/dist/trigger/types.js +2 -1
  45. package/package.json +15 -7
  46. package/sbom.spdx.json +5 -5
  47. package/dist/environment/index.js +0 -5
  48. package/dist/environment/multi-env.js +0 -38
@@ -2,7 +2,7 @@
2
2
  * Shared approval requirement + clause types.
3
3
  *
4
4
  * One normalized `ApprovalRequirement` is produced by both approval triggers —
5
- * a mandatory environment policy and an explicit SDK `approval` config — and is
5
+ * a mandatory context policy and an explicit SDK `approval` config — and is
6
6
  * consumed identically by the orchestrator gate, the resolver, the held-run
7
7
  * store, and the agent step round-trip. Pure Zod (no node built-ins), so this
8
8
  * module is safe in the browser-facing engine barrel.
@@ -26,9 +26,9 @@ export declare const HoldScope: z.ZodEnum<{
26
26
  step: "step";
27
27
  }>;
28
28
  export type HoldScope = z.infer<typeof HoldScope>;
29
- /** What triggered the hold: an environment policy (mandatory) or SDK code (explicit). */
29
+ /** What triggered the hold: a context policy (mandatory) or SDK code (explicit). */
30
30
  export declare const TriggerSource: z.ZodEnum<{
31
- environment: "environment";
31
+ context: "context";
32
32
  explicit: "explicit";
33
33
  }>;
34
34
  export type TriggerSource = z.infer<typeof TriggerSource>;
@@ -5,7 +5,7 @@ import { z } from "zod";
5
5
  * Shared approval requirement + clause types.
6
6
  *
7
7
  * One normalized `ApprovalRequirement` is produced by both approval triggers —
8
- * a mandatory environment policy and an explicit SDK `approval` config — and is
8
+ * a mandatory context policy and an explicit SDK `approval` config — and is
9
9
  * consumed identically by the orchestrator gate, the resolver, the held-run
10
10
  * store, and the agent step round-trip. Pure Zod (no node built-ins), so this
11
11
  * module is safe in the browser-facing engine barrel.
@@ -22,8 +22,8 @@ const HoldScope = z.enum([
22
22
  "job",
23
23
  "step"
24
24
  ]);
25
- /** What triggered the hold: an environment policy (mandatory) or SDK code (explicit). */
26
- const TriggerSource = z.enum(["environment", "explicit"]);
25
+ /** What triggered the hold: a context policy (mandatory) or SDK code (explicit). */
26
+ const TriggerSource = z.enum(["context", "explicit"]);
27
27
  /**
28
28
  * The normalized requirement attached to a held element. `clauses` is a flat
29
29
  * AND list; an empty list means "any approval-capable org member". `expiresAt`
@@ -71,7 +71,7 @@ const POLICY_BY_ACTION = {
71
71
  kind: "sample",
72
72
  allowedRate: .05
73
73
  },
74
- "environment.list.read": {
74
+ "context.list.read": {
75
75
  kind: "sample",
76
76
  allowedRate: .1
77
77
  },
@@ -83,11 +83,11 @@ const POLICY_BY_ACTION = {
83
83
  kind: "sample",
84
84
  allowedRate: .1
85
85
  },
86
- "environment.get.read": {
86
+ "context.get.read": {
87
87
  kind: "sample",
88
88
  allowedRate: .2
89
89
  },
90
- "environment.history.read": {
90
+ "context.history.read": {
91
91
  kind: "sample",
92
92
  allowedRate: .2
93
93
  },
@@ -95,7 +95,7 @@ const POLICY_BY_ACTION = {
95
95
  kind: "sample",
96
96
  allowedRate: .2
97
97
  },
98
- "env_binding.list.read": {
98
+ "context_binding.list.read": {
99
99
  kind: "sample",
100
100
  allowedRate: .2
101
101
  },
@@ -131,16 +131,16 @@ const POLICY_BY_ACTION = {
131
131
  "job.cancel": { kind: "always" },
132
132
  "event_log.detail.read": { kind: "always" },
133
133
  "event_log.payload.read": { kind: "always" },
134
- "environment.create": { kind: "always" },
135
- "environment.update": { kind: "always" },
136
- "environment.delete": { kind: "always" },
137
- "env_var.list.read": { kind: "always" },
138
- "env_var.set": { kind: "always" },
139
- "env_var.delete": { kind: "always" },
134
+ "context.create": { kind: "always" },
135
+ "context.update": { kind: "always" },
136
+ "context.delete": { kind: "always" },
137
+ "context_var.list.read": { kind: "always" },
138
+ "context_var.set": { kind: "always" },
139
+ "context_var.delete": { kind: "always" },
140
140
  "source_override.list.read": { kind: "always" },
141
141
  "source_override.set": { kind: "always" },
142
142
  "source_override.delete": { kind: "always" },
143
- "env_binding.set": { kind: "always" },
143
+ "context_binding.set": { kind: "always" },
144
144
  "secret.list.read": { kind: "always" },
145
145
  "secret.set": { kind: "always" },
146
146
  "secret.delete": { kind: "always" },
@@ -165,6 +165,7 @@ const POLICY_BY_ACTION = {
165
165
  "global_workflows.update": { kind: "always" },
166
166
  "org_settings.dashboard_write_policy.update": { kind: "always" },
167
167
  "cluster_name.update": { kind: "always" },
168
+ "attestation.retry": { kind: "always" },
168
169
  "access_log.list.read": { kind: "always" },
169
170
  "event_dlq.list.read": {
170
171
  kind: "sample",
@@ -21,13 +21,13 @@ const ACCESS_LOG_WARM_DAYS = {
21
21
  "step.logs.read": 30,
22
22
  "attestations.read": 30,
23
23
  "event_log.list.read": 30,
24
- "environment.list.read": 30,
25
- "environment.get.read": 30,
26
- "environment.history.read": 30,
24
+ "context.list.read": 30,
25
+ "context.get.read": 30,
26
+ "context.history.read": 30,
27
27
  "registration.list.read": 30,
28
28
  "global_workflows.get.read": 30,
29
29
  "held_run.list.read": 30,
30
- "env_binding.list.read": 30,
30
+ "context_binding.list.read": 30,
31
31
  "backend.list.read": 30,
32
32
  "backend.get.read": 30,
33
33
  "diagnostics.read": 30,
@@ -37,7 +37,7 @@ const ACCESS_LOG_WARM_DAYS = {
37
37
  "event_log.detail.read": 180,
38
38
  "event_log.payload.read": 180,
39
39
  "run.payload.read": 180,
40
- "env_var.list.read": 180,
40
+ "context_var.list.read": 180,
41
41
  "source_override.list.read": 180,
42
42
  "access_log.list.read": 180,
43
43
  "secret.list.read": 180,
@@ -46,14 +46,14 @@ const ACCESS_LOG_WARM_DAYS = {
46
46
  "run.manual_schedule": 180,
47
47
  "run.trigger": 180,
48
48
  "job.cancel": 180,
49
- "environment.create": 180,
50
- "environment.update": 180,
51
- "environment.delete": 180,
52
- "env_var.set": 180,
53
- "env_var.delete": 180,
49
+ "context.create": 180,
50
+ "context.update": 180,
51
+ "context.delete": 180,
52
+ "context_var.set": 180,
53
+ "context_var.delete": 180,
54
54
  "source_override.set": 180,
55
55
  "source_override.delete": 180,
56
- "env_binding.set": 180,
56
+ "context_binding.set": 180,
57
57
  "held_run.approve": 180,
58
58
  "held_run.auto_approve": 180,
59
59
  "held_run.reject": 180,
@@ -71,6 +71,7 @@ const ACCESS_LOG_WARM_DAYS = {
71
71
  "global_workflows.update": 180,
72
72
  "org_settings.dashboard_write_policy.update": 180,
73
73
  "cluster_name.update": 180,
74
+ "attestation.retry": 180,
74
75
  "event_dlq.list.read": 30,
75
76
  "event_dlq.retry": 180,
76
77
  "event_dlq.discard": 180,
@@ -266,13 +267,13 @@ const ACCESS_LOG_COLD_DAYS = {
266
267
  "step.logs.read": 180,
267
268
  "attestations.read": 180,
268
269
  "event_log.list.read": 180,
269
- "environment.list.read": 180,
270
- "environment.get.read": 180,
271
- "environment.history.read": 180,
270
+ "context.list.read": 180,
271
+ "context.get.read": 180,
272
+ "context.history.read": 180,
272
273
  "registration.list.read": 180,
273
274
  "global_workflows.get.read": 180,
274
275
  "held_run.list.read": 180,
275
- "env_binding.list.read": 180,
276
+ "context_binding.list.read": 180,
276
277
  "backend.list.read": 180,
277
278
  "backend.get.read": 180,
278
279
  "diagnostics.read": 30,
@@ -282,7 +283,7 @@ const ACCESS_LOG_COLD_DAYS = {
282
283
  "event_log.detail.read": 730,
283
284
  "event_log.payload.read": 730,
284
285
  "run.payload.read": 730,
285
- "env_var.list.read": 730,
286
+ "context_var.list.read": 730,
286
287
  "source_override.list.read": 730,
287
288
  "access_log.list.read": 730,
288
289
  "secret.list.read": 730,
@@ -291,14 +292,14 @@ const ACCESS_LOG_COLD_DAYS = {
291
292
  "run.manual_schedule": 730,
292
293
  "run.trigger": 730,
293
294
  "job.cancel": 730,
294
- "environment.create": 730,
295
- "environment.update": 730,
296
- "environment.delete": 730,
297
- "env_var.set": 730,
298
- "env_var.delete": 730,
295
+ "context.create": 730,
296
+ "context.update": 730,
297
+ "context.delete": 730,
298
+ "context_var.set": 730,
299
+ "context_var.delete": 730,
299
300
  "source_override.set": 730,
300
301
  "source_override.delete": 730,
301
- "env_binding.set": 730,
302
+ "context_binding.set": 730,
302
303
  "held_run.approve": 730,
303
304
  "held_run.auto_approve": 730,
304
305
  "held_run.reject": 730,
@@ -316,6 +317,7 @@ const ACCESS_LOG_COLD_DAYS = {
316
317
  "global_workflows.update": 730,
317
318
  "org_settings.dashboard_write_policy.update": 730,
318
319
  "cluster_name.update": 730,
320
+ "attestation.retry": 730,
319
321
  "event_dlq.list.read": 180,
320
322
  "event_dlq.retry": 730,
321
323
  "event_dlq.discard": 730,
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Identity facts of a single fan-out child, matched against a binding's
3
+ * `host_pattern`. `agentId` / `host` are the stable dispatch identity; `labels`
4
+ * is the host's label set. The union of all three is the match target.
5
+ */
6
+ export interface HostFacts {
7
+ agentId: string;
8
+ host: string;
9
+ labels: readonly string[];
10
+ }
11
+ /**
12
+ * Whether a fan-out child's identity facts satisfy a binding's `host_pattern`.
13
+ *
14
+ * `'**'` / empty matches every host. Otherwise the pattern is compiled once
15
+ * (exact / glob / regex, same selector grammar as `runsOnAll`) and tested
16
+ * against the union `[agentId, host, ...labels]` — true if any element matches.
17
+ */
18
+ export declare function matchHostPattern(facts: HostFacts, pattern: string): boolean;
19
+ /**
20
+ * Rank a `host_pattern` by specificity for precedence: an exact literal (2)
21
+ * beats a glob/regex (1), which beats `'**'`/empty (0). Used to let a per-host
22
+ * binding override a fleet-wide one on a key collision.
23
+ */
24
+ export declare function hostSpecificity(pattern: string): number;
25
+ //# sourceMappingURL=host-match.d.ts.map
@@ -1,7 +1,7 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { matcherMatches } from "../labels-match.js";
3
3
  import { assertSafeRegex, toLabelMatcher } from "../labels/compile.js";
4
- //#region src/environment/host-match.ts
4
+ //#region src/context/host-match.ts
5
5
  /** `'**'`, empty, or absent means "matches every host". */
6
6
  function matchesAllHosts(pattern) {
7
7
  return pattern === "" || pattern === "**";
@@ -0,0 +1,6 @@
1
+ export type { Context, ContextBinding, ContextVariable, ContextSourceOverride, ScopedSecret, HeldRun, ProtectionGateResult, TrustTier, } from './types.js';
2
+ export { TrustTierSchema } from './types.js';
3
+ export { resolveSecretsForContext, matchScopePattern, stripScopePrefix } from './scope-resolver.js';
4
+ export type { HostFacts } from './host-match.js';
5
+ export { mergeOrderedMaps, ContextGateRejectReason } from './multi-context.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { TrustTierSchema } from "./types.js";
3
+ import { matchScopePattern, resolveSecretsForContext, stripScopePrefix } from "./scope-resolver.js";
4
+ import { ContextGateRejectReason, mergeOrderedMaps } from "./multi-context.js";
5
+ export { ContextGateRejectReason, TrustTierSchema, matchScopePattern, mergeOrderedMaps, resolveSecretsForContext, stripScopePrefix };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Multi-context merge helpers shared across the orchestrator dispatch path.
3
+ *
4
+ * A job may bind several contexts in order; their resolved
5
+ * secrets/variables are folded last-wins (a later context's key overrides an
6
+ * earlier one) and their protection gates combine all-must-pass. This module is
7
+ * browser-safe (pure functions + a Zod enum, no Node built-ins) so it can be
8
+ * exported from the engine context barrel.
9
+ */
10
+ import { z } from 'zod';
11
+ /**
12
+ * Reason a single bound context rejects a run under all-must-pass
13
+ * aggregation. Used to name which context and which rule blocked dispatch.
14
+ */
15
+ export declare const ContextGateRejectReason: z.ZodEnum<{
16
+ branch_restricted: "branch_restricted";
17
+ trigger_filtered: "trigger_filtered";
18
+ repo_unmatched: "repo_unmatched";
19
+ trust_too_low: "trust_too_low";
20
+ context_disabled: "context_disabled";
21
+ context_not_found: "context_not_found";
22
+ }>;
23
+ export type ContextGateRejectReason = z.infer<typeof ContextGateRejectReason>;
24
+ /**
25
+ * Fold an ordered list of per-context resolved maps into one. Later entries
26
+ * override earlier keys (last-wins), matching the documented merge order for
27
+ * `contexts: [...]`.
28
+ */
29
+ export declare function mergeOrderedMaps(maps: ReadonlyArray<Record<string, string>>): Record<string, string>;
30
+ //# sourceMappingURL=multi-context.d.ts.map
@@ -0,0 +1,38 @@
1
+ import "../rolldown-runtime-ClRpJifh.js";
2
+ import { z } from "zod";
3
+ //#region src/context/multi-context.ts
4
+ /**
5
+ * Multi-context merge helpers shared across the orchestrator dispatch path.
6
+ *
7
+ * A job may bind several contexts in order; their resolved
8
+ * secrets/variables are folded last-wins (a later context's key overrides an
9
+ * earlier one) and their protection gates combine all-must-pass. This module is
10
+ * browser-safe (pure functions + a Zod enum, no Node built-ins) so it can be
11
+ * exported from the engine context barrel.
12
+ */
13
+ /**
14
+ * Reason a single bound context rejects a run under all-must-pass
15
+ * aggregation. Used to name which context and which rule blocked dispatch.
16
+ */
17
+ const ContextGateRejectReason = z.enum([
18
+ "branch_restricted",
19
+ "trigger_filtered",
20
+ "repo_unmatched",
21
+ "trust_too_low",
22
+ "context_disabled",
23
+ "context_not_found"
24
+ ]);
25
+ /**
26
+ * Fold an ordered list of per-context resolved maps into one. Later entries
27
+ * override earlier keys (last-wins), matching the documented merge order for
28
+ * `contexts: [...]`.
29
+ */
30
+ function mergeOrderedMaps(maps) {
31
+ const out = {};
32
+ for (const m of maps) Object.assign(out, m);
33
+ return out;
34
+ }
35
+ //#endregion
36
+ export { ContextGateRejectReason, mergeOrderedMaps };
37
+
38
+ //# sourceMappingURL=multi-context.js.map
@@ -0,0 +1,46 @@
1
+ import type { ContextBinding, ScopedSecret } from './types.js';
2
+ import { type HostFacts } from './host-match.js';
3
+ export type { HostFacts } from './host-match.js';
4
+ /**
5
+ * Check whether a scope string matches a pattern.
6
+ *
7
+ * Supports exact match and glob patterns (via picomatch).
8
+ * Scope paths use '/' as separator (e.g., 'aws/prod/db').
9
+ *
10
+ * For prefixed scopes (e.g., 'pg:aws/prod'), the pattern may be prefixed too
11
+ * (e.g., 'pg:**'). In this case, the backend prefix must match exactly and
12
+ * the path portion is matched separately against the glob. This is needed
13
+ * because picomatch's '**' requires '/' separators — 'pg:**' wouldn't match
14
+ * 'pg:aws/prod' without splitting on the colon.
15
+ */
16
+ export declare function matchScopePattern(scope: string, pattern: string): boolean;
17
+ /**
18
+ * Strip the backend prefix from a scope string.
19
+ * Prefixed scopes have the form "backendName:path" (e.g., "pg:aws/prod").
20
+ * Returns the path after the first colon, or the full scope if no prefix.
21
+ */
22
+ export declare function stripScopePrefix(scope: string): string;
23
+ /**
24
+ * Resolve secrets for a context by matching bindings against scoped secrets.
25
+ *
26
+ * Takes already-filtered bindings (for the target context). For each binding,
27
+ * finds secrets whose (substituted) scope matches the binding's scopePattern via
28
+ * picomatch. When multiple scopes provide the same key, precedence is the tuple
29
+ * `(host specificity, scope depth)` — a per-host binding (exact host) overrides a
30
+ * fleet-wide one, then longest scope path wins. Scope depth is computed AFTER
31
+ * stripping the backend prefix.
32
+ *
33
+ * When `hostFacts` is supplied (a fan-out child's identity), each binding is
34
+ * gated by its `host_pattern` and its `scope_pattern` is templated per-child
35
+ * (`${agentId}`/`${host}`/`${label:NAME}`). When omitted, only fleet-wide
36
+ * (`'**'`/NULL) non-templated bindings contribute — preserving the workflow-level
37
+ * (no-host) behaviour.
38
+ *
39
+ * @param bindings - Bindings already filtered for the target context
40
+ * @param allSecrets - All scoped secrets in the org
41
+ * @param decryptFn - Pure decryption function (keeps this module crypto-free)
42
+ * @param hostFacts - Optional fan-out child identity for per-host resolution
43
+ * @returns Flat record of decrypted secret key-value pairs
44
+ */
45
+ export declare function resolveSecretsForContext(bindings: ContextBinding[], allSecrets: ScopedSecret[], decryptFn: (s: ScopedSecret) => string, hostFacts?: HostFacts): Record<string, string>;
46
+ //# sourceMappingURL=scope-resolver.d.ts.map
@@ -2,7 +2,7 @@ import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { hostSpecificity, matchHostPattern } from "./host-match.js";
3
3
  import { substituteScopePattern } from "./scope-template.js";
4
4
  import picomatch from "picomatch";
5
- //#region src/environment/scope-resolver.ts
5
+ //#region src/context/scope-resolver.ts
6
6
  /**
7
7
  * Check whether a scope string matches a pattern.
8
8
  *
@@ -70,9 +70,9 @@ function candidateWins(c, existing) {
70
70
  return c.scopeDepth > existing.scopeDepth;
71
71
  }
72
72
  /**
73
- * Resolve secrets for an environment by matching bindings against scoped secrets.
73
+ * Resolve secrets for a context by matching bindings against scoped secrets.
74
74
  *
75
- * Takes already-filtered bindings (for the target environment). For each binding,
75
+ * Takes already-filtered bindings (for the target context). For each binding,
76
76
  * finds secrets whose (substituted) scope matches the binding's scopePattern via
77
77
  * picomatch. When multiple scopes provide the same key, precedence is the tuple
78
78
  * `(host specificity, scope depth)` — a per-host binding (exact host) overrides a
@@ -85,13 +85,13 @@ function candidateWins(c, existing) {
85
85
  * (`'**'`/NULL) non-templated bindings contribute — preserving the workflow-level
86
86
  * (no-host) behaviour.
87
87
  *
88
- * @param bindings - Bindings already filtered for the target environment
88
+ * @param bindings - Bindings already filtered for the target context
89
89
  * @param allSecrets - All scoped secrets in the org
90
90
  * @param decryptFn - Pure decryption function (keeps this module crypto-free)
91
91
  * @param hostFacts - Optional fan-out child identity for per-host resolution
92
92
  * @returns Flat record of decrypted secret key-value pairs
93
93
  */
94
- function resolveSecretsForEnvironment(bindings, allSecrets, decryptFn, hostFacts) {
94
+ function resolveSecretsForContext(bindings, allSecrets, decryptFn, hostFacts) {
95
95
  const resolved = /* @__PURE__ */ new Map();
96
96
  for (const binding of bindings) {
97
97
  const scopePattern = bindingScopeForHost(binding, hostFacts);
@@ -112,6 +112,6 @@ function resolveSecretsForEnvironment(bindings, allSecrets, decryptFn, hostFacts
112
112
  return result;
113
113
  }
114
114
  //#endregion
115
- export { matchScopePattern, resolveSecretsForEnvironment, stripScopePrefix };
115
+ export { matchScopePattern, resolveSecretsForContext, stripScopePrefix };
116
116
 
117
117
  //# sourceMappingURL=scope-resolver.js.map
@@ -0,0 +1,18 @@
1
+ import type { HostFacts } from './host-match.js';
2
+ /**
3
+ * Substitute `${agentId}` / `${host}` / `${label:NAME}` placeholders in a
4
+ * binding's `scope_pattern` with a fan-out child's identity, so one templated
5
+ * binding selects each host's own subtree (`prod/hosts/${agentId}/**`).
6
+ *
7
+ * Returns the substituted pattern, or `null` when the binding must be **skipped
8
+ * for this host** because either:
9
+ * - a referenced variable is unresolved (a missing `${label:NAME}`), or
10
+ * - a substituted value is unsafe — it contains anything outside
11
+ * `[A-Za-z0-9._-]` (a `/` path separator or a glob metacharacter), which
12
+ * could let a hostname/label value escape its segment or inject a pattern.
13
+ *
14
+ * A multi-valued label resolves to its lexicographic-first value
15
+ * (deterministic). A pattern with no placeholders is returned unchanged.
16
+ */
17
+ export declare function substituteScopePattern(pattern: string, facts: HostFacts): string | null;
18
+ //# sourceMappingURL=scope-template.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
- //#region src/environment/scope-template.ts
2
+ //#region src/context/scope-template.ts
3
3
  /** A substituted value must be a single literal path segment — no `/` or glob. */
4
4
  const SAFE_SEGMENT = /^[A-Za-z0-9._-]+$/;
5
5
  const PLACEHOLDER = /\$\{(agentId|host|label:[^}]+)\}/g;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Context types for KiCI's named-context model.
3
+ *
4
+ * Contexts are org-level entities that group secrets, variables,
5
+ * and protection rules for deployment targets (dev, staging, production).
6
+ */
7
+ import { z } from 'zod';
8
+ import type { ApproverClause } from '../approval/types.js';
9
+ /** Context entity — org-level deployment target with protection rules. */
10
+ export interface Context {
11
+ id: string;
12
+ orgId: string;
13
+ name: string;
14
+ type: 'fixed' | 'glob';
15
+ globPattern: string | null;
16
+ branchRestrictions: string[];
17
+ triggerTypeFilters: string[];
18
+ repoPatterns: string[];
19
+ concurrencyLimit: number | null;
20
+ concurrencyStrategy: 'queue' | 'cancel-pending';
21
+ concurrencyTimeoutMs: number;
22
+ requiredReviewers: string[] | null;
23
+ waitTimerSeconds: number | null;
24
+ holdExpirySeconds: number;
25
+ /** Minimum trust tier required for CI execution in this context. */
26
+ minimumTrust?: 'known' | 'trusted';
27
+ /** Whether this context allows local (no-remote) executions. Default false. */
28
+ allowLocalExecution?: boolean;
29
+ enabled: boolean;
30
+ createdAt: string;
31
+ updatedAt: string;
32
+ createdBy: string;
33
+ }
34
+ /** Scoped secret — individual secret with a scope path for precedence resolution. */
35
+ export interface ScopedSecret {
36
+ id: string;
37
+ orgId: string;
38
+ scope: string;
39
+ key: string;
40
+ encryptedValue: string;
41
+ backendType: 'pg' | 'vault';
42
+ keyVersion: number;
43
+ createdAt: string;
44
+ updatedAt: string;
45
+ }
46
+ /** Binding that maps a scope pattern to a context. */
47
+ export interface ContextBinding {
48
+ id: string;
49
+ orgId: string;
50
+ contextId: string;
51
+ scopePattern: string;
52
+ /**
53
+ * Host selector this binding applies to (exact / glob / regex, matched
54
+ * against a fan-out child's agentId / hostname / labels). `'**'` matches
55
+ * every host, preserving fleet-wide behaviour for bindings with no host
56
+ * scope.
57
+ */
58
+ hostPattern: string;
59
+ createdAt: string;
60
+ }
61
+ /** Non-secret key-value config per context, with optional lock. */
62
+ export interface ContextVariable {
63
+ id: string;
64
+ orgId: string;
65
+ contextId: string;
66
+ key: string;
67
+ value: string;
68
+ locked: boolean;
69
+ createdAt: string;
70
+ updatedAt: string;
71
+ }
72
+ /** Per-source override for a context variable. */
73
+ export interface ContextSourceOverride {
74
+ id: string;
75
+ orgId: string;
76
+ contextId: string;
77
+ routingKey: string;
78
+ key: string;
79
+ value: string;
80
+ createdAt: string;
81
+ updatedAt: string;
82
+ }
83
+ /** Trust tier for contributor-based CI execution gating (single source of truth). */
84
+ export declare const TrustTierSchema: z.ZodEnum<{
85
+ unknown: "unknown";
86
+ known: "known";
87
+ trusted: "trusted";
88
+ }>;
89
+ export type TrustTier = z.infer<typeof TrustTierSchema>;
90
+ /** Held run record for protection gate enforcement. */
91
+ export interface HeldRun {
92
+ id: string;
93
+ orgId: string;
94
+ runId: string;
95
+ jobId: string;
96
+ contextId: string;
97
+ holdType: 'reviewer' | 'timer' | 'concurrency' | 'security';
98
+ status: 'pending' | 'approved' | 'rejected' | 'expired';
99
+ reason: string | null;
100
+ approvedBy: string | null;
101
+ createdAt: string;
102
+ expiresAt: string | null;
103
+ resolvedAt: string | null;
104
+ }
105
+ /** Result from the protection gate pipeline evaluation. */
106
+ export interface ProtectionGateResult {
107
+ action: 'pass' | 'reject' | 'hold' | 'queue' | 'wait';
108
+ reason?: string;
109
+ holdUntil?: string;
110
+ holdType?: 'reviewer' | 'timer' | 'concurrency' | 'security';
111
+ /**
112
+ * Approver clauses for a reviewer hold, mapped from the context's
113
+ * `requiredReviewers`. Each reviewer string maps to a `{ user }` clause
114
+ * (team-named reviewers are a documented follow-up). Empty/undefined means
115
+ * "any approval-capable member".
116
+ */
117
+ clauses?: ApproverClause[];
118
+ }
119
+ //# sourceMappingURL=types.d.ts.map
@@ -1,10 +1,10 @@
1
1
  import "../rolldown-runtime-ClRpJifh.js";
2
2
  import { z } from "zod";
3
- //#region src/environment/types.ts
3
+ //#region src/context/types.ts
4
4
  /**
5
- * Environment types for KiCI's deployment environment model.
5
+ * Context types for KiCI's named-context model.
6
6
  *
7
- * Environments are org-level entities that group secrets, variables,
7
+ * Contexts are org-level entities that group secrets, variables,
8
8
  * and protection rules for deployment targets (dev, staging, production).
9
9
  */
10
10
  /** Trust tier for contributor-based CI execution gating (single source of truth). */
@@ -21,7 +21,7 @@
21
21
  * Browser-safe: data + TypeScript types only, no Node imports, so it lives in
22
22
  * the engine barrel importable by the web UI, the CLI, and the Platform.
23
23
  */
24
- export type DeveloperOpDomain = 'runs' | 'workflows' | 'environments' | 'secrets' | 'held-runs' | 'diagnostics' | 'orchestrators' | 'sources' | 'dlq' | 'attestations' | 'activity' | 'orgs';
24
+ export type DeveloperOpDomain = 'runs' | 'workflows' | 'contexts' | 'secrets' | 'held-runs' | 'diagnostics' | 'orchestrators' | 'sources' | 'dlq' | 'attestations' | 'activity' | 'orgs';
25
25
  export type DeveloperOpKind = 'read' | 'write';
26
26
  /** Which of the three entrypoints a developer op is (or should be) exposed on. */
27
27
  export interface DeveloperOpEntrypoints {
@@ -88,7 +88,7 @@ const DEVELOPER_OPERATIONS = [
88
88
  mcp: false,
89
89
  ui: true
90
90
  }, false, null),
91
- op("environments.delete", "environments", "write", {
91
+ op("contexts.delete", "contexts", "write", {
92
92
  http: true,
93
93
  cli: false,
94
94
  mcp: false,
@@ -42,4 +42,27 @@ export declare const AGENT_REQUIRED_KICI_VARS: readonly ["KICI_ORCHESTRATOR_URL"
42
42
  * -> HTTP_PROXY=http://proxy:3128 in the agent process
43
43
  */
44
44
  export declare const KICI_AGENT_ENV_PREFIX: "KICI_AGENT_ENV_";
45
+ /**
46
+ * Non-`KICI_`-prefixed environment variables that are the agent's / orchestrator's
47
+ * own infrastructure secrets. These are scrubbed from a trusted-env passthrough
48
+ * in addition to the whole `KICI_*` namespace, so even a trusted fleet agent
49
+ * never leaks its control-plane credentials into a workflow step.
50
+ */
51
+ export declare const TRUSTED_ENV_SCRUB_EXACT: readonly ["DATABASE_URL", "PLATFORM_TOKEN", "WEBHOOK_SECRET", "GITHUB_PRIVATE_KEY"];
52
+ /**
53
+ * A variable that must NEVER reach a workflow step even under the trusted-env
54
+ * profile. The agent's entire `KICI_*` namespace (its orchestrator URL, agent
55
+ * token, secret key, bootstrap admin token, scaler internals, identity) is
56
+ * scrubbed, plus the non-`KICI_` infra-secret denylist above. So "trusted"
57
+ * means "host env yes, the agent's KiCI identity no".
58
+ */
59
+ export declare function isTrustedEnvScrubbed(key: string): boolean;
60
+ /**
61
+ * Build the trusted-env passthrough set: every defined entry of `source` whose
62
+ * key is not scrubbed by `isTrustedEnvScrubbed`. Used by both env-narrowing
63
+ * layers (scaler → agent process, agent → step) when the trusted-env profile is
64
+ * active, so the ambient host env reaches the step minus the agent's own KiCI
65
+ * identity/operational secrets.
66
+ */
67
+ export declare function buildTrustedPassthroughEnv(source: Record<string, string | undefined>): Record<string, string>;
45
68
  //# sourceMappingURL=environment-allowlist.d.ts.map