@kici-dev/engine 0.1.26 → 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.
- package/dist/approval/types.d.ts +3 -3
- package/dist/approval/types.js +3 -3
- package/dist/audit/access-log-policy.js +12 -11
- package/dist/audit/retention-policy.js +24 -22
- package/dist/context/host-match.d.ts +25 -0
- package/dist/{environment → context}/host-match.js +1 -1
- package/dist/context/index.d.ts +6 -0
- package/dist/context/index.js +5 -0
- package/dist/context/multi-context.d.ts +30 -0
- package/dist/context/multi-context.js +38 -0
- package/dist/context/scope-resolver.d.ts +46 -0
- package/dist/{environment → context}/scope-resolver.js +6 -6
- package/dist/context/scope-template.d.ts +18 -0
- package/dist/{environment → context}/scope-template.js +1 -1
- package/dist/context/types.d.ts +119 -0
- package/dist/{environment → context}/types.js +3 -3
- package/dist/dev-ops/operations.d.ts +1 -1
- package/dist/dev-ops/operations.js +1 -1
- package/dist/env/environment-allowlist.d.ts +23 -0
- package/dist/env/environment-allowlist.js +35 -1
- package/dist/fanout/materialize.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -8
- package/dist/metrics/metric-catalog.generated.d.ts +15 -10
- package/dist/metrics/metric-catalog.generated.js +18 -12
- package/dist/protocol/dashboard-api-errors.d.ts +12 -0
- package/dist/protocol/dashboard-api-errors.js +13 -0
- package/dist/protocol/dashboard-write-operations.d.ts +22 -22
- package/dist/protocol/dashboard-write-operations.js +52 -52
- package/dist/protocol/messages/access-log.d.ts +65 -60
- package/dist/protocol/messages/access-log.js +13 -12
- package/dist/protocol/messages/agent-run-result.d.ts +2 -2
- package/dist/protocol/messages/agent-run-result.js +1 -1
- package/dist/protocol/messages/auth.d.ts +7 -7
- package/dist/protocol/messages/capabilities.d.ts +7 -7
- package/dist/protocol/messages/dashboard.d.ts +235 -233
- package/dist/protocol/messages/dashboard.js +191 -191
- package/dist/protocol/messages/execution-status.d.ts +9 -9
- package/dist/protocol/messages/execution-status.js +8 -8
- package/dist/protocol/messages/platform-orchestrator.d.ts +75 -74
- package/dist/protocol/session-policy.d.ts +20 -0
- package/dist/protocol/session-policy.js +25 -0
- package/dist/trigger/types.d.ts +7 -6
- package/dist/trigger/types.js +2 -1
- package/package.json +15 -7
- package/sbom.spdx.json +5 -5
- package/dist/environment/index.js +0 -5
- package/dist/environment/multi-env.js +0 -38
package/dist/approval/types.d.ts
CHANGED
|
@@ -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
|
|
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:
|
|
29
|
+
/** What triggered the hold: a context policy (mandatory) or SDK code (explicit). */
|
|
30
30
|
export declare const TriggerSource: z.ZodEnum<{
|
|
31
|
-
|
|
31
|
+
context: "context";
|
|
32
32
|
explicit: "explicit";
|
|
33
33
|
}>;
|
|
34
34
|
export type TriggerSource = z.infer<typeof TriggerSource>;
|
package/dist/approval/types.js
CHANGED
|
@@ -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
|
|
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:
|
|
26
|
-
const TriggerSource = z.enum(["
|
|
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
|
-
"
|
|
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
|
-
"
|
|
86
|
+
"context.get.read": {
|
|
87
87
|
kind: "sample",
|
|
88
88
|
allowedRate: .2
|
|
89
89
|
},
|
|
90
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
270
|
-
"
|
|
271
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
295
|
-
"
|
|
296
|
-
"
|
|
297
|
-
"
|
|
298
|
-
"
|
|
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
|
-
"
|
|
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/
|
|
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/
|
|
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
|
|
73
|
+
* Resolve secrets for a context by matching bindings against scoped secrets.
|
|
74
74
|
*
|
|
75
|
-
* Takes already-filtered bindings (for the target
|
|
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
|
|
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
|
|
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,
|
|
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/
|
|
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/
|
|
3
|
+
//#region src/context/types.ts
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* Context types for KiCI's named-context model.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
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' | '
|
|
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 {
|
|
@@ -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
|