@kici-dev/sdk 0.0.0 → 0.1.1
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/LICENSE +202 -0
- package/README.md +1 -6
- package/dist/api-types.d.ts +47 -0
- package/dist/api-types.js +15 -0
- package/dist/chunk-gOLHoazu.js +4 -0
- package/dist/context.d.ts +185 -0
- package/dist/context.js +2 -0
- package/dist/dynamic-group.d.ts +29 -0
- package/dist/dynamic-group.js +34 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.js +17 -0
- package/dist/events/define-event.d.ts +32 -0
- package/dist/events/define-event.js +29 -0
- package/dist/events/event-payloads.d.ts +396 -0
- package/dist/events/event-payloads.js +21 -0
- package/dist/events/index.d.ts +6 -0
- package/dist/events/index.js +4 -0
- package/dist/events/types.d.ts +13 -0
- package/dist/events/types.js +2 -0
- package/dist/fixture.d.ts +50 -0
- package/dist/fixture.js +35 -0
- package/dist/hooks/index.d.ts +33 -0
- package/dist/hooks/index.js +94 -0
- package/dist/hooks/types.d.ts +35 -0
- package/dist/hooks/types.js +2 -0
- package/dist/idempotent.d.ts +71 -0
- package/dist/idempotent.js +77 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +50 -0
- package/dist/job.d.ts +31 -0
- package/dist/job.js +46 -0
- package/dist/matrix/expand.d.ts +32 -0
- package/dist/matrix/expand.js +77 -0
- package/dist/matrix/index.d.ts +4 -0
- package/dist/matrix/index.js +4 -0
- package/dist/matrix/types.d.ts +60 -0
- package/dist/matrix/types.js +18 -0
- package/dist/outputs.d.ts +86 -0
- package/dist/outputs.js +180 -0
- package/dist/rules/evaluator.d.ts +24 -0
- package/dist/rules/evaluator.js +52 -0
- package/dist/rules/index.d.ts +6 -0
- package/dist/rules/index.js +5 -0
- package/dist/rules/rule.d.ts +34 -0
- package/dist/rules/rule.js +37 -0
- package/dist/rules/types.d.ts +42 -0
- package/dist/rules/types.js +2 -0
- package/dist/secrets.d.ts +192 -0
- package/dist/secrets.js +132 -0
- package/dist/step.d.ts +50 -0
- package/dist/step.js +78 -0
- package/dist/triggers/comment.d.ts +20 -0
- package/dist/triggers/comment.js +47 -0
- package/dist/triggers/create.d.ts +20 -0
- package/dist/triggers/create.js +32 -0
- package/dist/triggers/delete.d.ts +20 -0
- package/dist/triggers/delete.js +29 -0
- package/dist/triggers/dispatch.d.ts +17 -0
- package/dist/triggers/dispatch.js +27 -0
- package/dist/triggers/fork.d.ts +17 -0
- package/dist/triggers/fork.js +26 -0
- package/dist/triggers/generic-webhook.d.ts +32 -0
- package/dist/triggers/generic-webhook.js +45 -0
- package/dist/triggers/index.d.ts +28 -0
- package/dist/triggers/index.js +25 -0
- package/dist/triggers/job-complete.d.ts +23 -0
- package/dist/triggers/job-complete.js +33 -0
- package/dist/triggers/kici-event.d.ts +23 -0
- package/dist/triggers/kici-event.js +34 -0
- package/dist/triggers/lifecycle.d.ts +20 -0
- package/dist/triggers/lifecycle.js +29 -0
- package/dist/triggers/pr.d.ts +27 -0
- package/dist/triggers/pr.js +48 -0
- package/dist/triggers/push.d.ts +29 -0
- package/dist/triggers/push.js +48 -0
- package/dist/triggers/release.d.ts +17 -0
- package/dist/triggers/release.js +27 -0
- package/dist/triggers/review-comment.d.ts +17 -0
- package/dist/triggers/review-comment.js +27 -0
- package/dist/triggers/review.d.ts +17 -0
- package/dist/triggers/review.js +28 -0
- package/dist/triggers/schedule.d.ts +20 -0
- package/dist/triggers/schedule.js +29 -0
- package/dist/triggers/star.d.ts +17 -0
- package/dist/triggers/star.js +27 -0
- package/dist/triggers/status.d.ts +17 -0
- package/dist/triggers/status.js +28 -0
- package/dist/triggers/tag.d.ts +20 -0
- package/dist/triggers/tag.js +31 -0
- package/dist/triggers/types.d.ts +529 -0
- package/dist/triggers/types.js +36 -0
- package/dist/triggers/watch.d.ts +17 -0
- package/dist/triggers/watch.js +27 -0
- package/dist/triggers/webhook.d.ts +19 -0
- package/dist/triggers/webhook.js +29 -0
- package/dist/triggers/workflow-complete.d.ts +23 -0
- package/dist/triggers/workflow-complete.js +32 -0
- package/dist/triggers/workflow-run.d.ts +17 -0
- package/dist/triggers/workflow-run.js +29 -0
- package/dist/types.d.ts +483 -0
- package/dist/types.js +35 -0
- package/dist/validation/dag.d.ts +42 -0
- package/dist/validation/dag.js +70 -0
- package/dist/validation/index.d.ts +3 -0
- package/dist/validation/index.js +3 -0
- package/dist/wait-for.d.ts +109 -0
- package/dist/wait-for.js +144 -0
- package/dist/workflow.d.ts +3 -0
- package/dist/workflow.js +83 -0
- package/package.json +42 -5
- package/sbom.spdx.json +9150 -0
- package/index.js +0 -3
package/dist/outputs.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import "./chunk-gOLHoazu.js";
|
|
2
|
+
//#region src/outputs.ts
|
|
3
|
+
/**
|
|
4
|
+
* Well-known string property names that should delegate to Reflect rather than throwing.
|
|
5
|
+
* These are accessed by built-in operations like JSON.stringify, console.log, iteration, etc.
|
|
6
|
+
*/
|
|
7
|
+
const WELL_KNOWN_STRING_PROPS = new Set([
|
|
8
|
+
"constructor",
|
|
9
|
+
"toString",
|
|
10
|
+
"valueOf",
|
|
11
|
+
"toJSON",
|
|
12
|
+
"then",
|
|
13
|
+
"length",
|
|
14
|
+
"nodeType",
|
|
15
|
+
"tagName",
|
|
16
|
+
"inspect",
|
|
17
|
+
"$$typeof",
|
|
18
|
+
"asymmetricMatch",
|
|
19
|
+
"_tag"
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Module-global outputs maps. Runners inject fresh maps at execution time
|
|
23
|
+
* via setStepOutputsMap() / setJobOutputsMap().
|
|
24
|
+
*/
|
|
25
|
+
let _stepOutputsMap = /* @__PURE__ */ new Map();
|
|
26
|
+
let _jobOutputsMap = /* @__PURE__ */ new Map();
|
|
27
|
+
let _stepRefMap = /* @__PURE__ */ new WeakMap();
|
|
28
|
+
/**
|
|
29
|
+
* Inject a fresh step outputs map for a new execution.
|
|
30
|
+
* Called by workflow runners (compiler test runner, agent sandbox) before execution.
|
|
31
|
+
*/
|
|
32
|
+
function setStepOutputsMap(map) {
|
|
33
|
+
_stepOutputsMap = map;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Inject a fresh job outputs map for a new execution.
|
|
37
|
+
*/
|
|
38
|
+
function setJobOutputsMap(map) {
|
|
39
|
+
_jobOutputsMap = map;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Inject a fresh step-ref map for bare function -> step name resolution.
|
|
43
|
+
*/
|
|
44
|
+
function setStepRefMap(map) {
|
|
45
|
+
_stepRefMap = map;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get the current step outputs map (for runners to populate).
|
|
49
|
+
*/
|
|
50
|
+
function getStepOutputsMap() {
|
|
51
|
+
return _stepOutputsMap;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the current job outputs map (for runners to populate).
|
|
55
|
+
*/
|
|
56
|
+
function getJobOutputsMap() {
|
|
57
|
+
return _jobOutputsMap;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get the current step ref map.
|
|
61
|
+
*/
|
|
62
|
+
function getStepRefMap() {
|
|
63
|
+
return _stepRefMap;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a Proxy over step outputs that resolves property access lazily
|
|
67
|
+
* against the module-global step outputs map.
|
|
68
|
+
*
|
|
69
|
+
* @param stepName - The name of the step whose outputs to proxy
|
|
70
|
+
* @returns A Proxy that resolves property access at runtime
|
|
71
|
+
*/
|
|
72
|
+
function createStepOutputProxy(stepName) {
|
|
73
|
+
return new Proxy({}, {
|
|
74
|
+
get(_target, prop, receiver) {
|
|
75
|
+
if (typeof prop === "symbol") return Reflect.get(_target, prop, receiver);
|
|
76
|
+
if (WELL_KNOWN_STRING_PROPS.has(prop)) return Reflect.get(_target, prop, receiver);
|
|
77
|
+
const outputs = _stepOutputsMap.get(stepName);
|
|
78
|
+
if (!outputs) throw new Error(`Step '${stepName}' has not produced outputs yet`);
|
|
79
|
+
return outputs[prop];
|
|
80
|
+
},
|
|
81
|
+
ownKeys() {
|
|
82
|
+
const outputs = _stepOutputsMap.get(stepName);
|
|
83
|
+
if (!outputs) return [];
|
|
84
|
+
return Reflect.ownKeys(outputs);
|
|
85
|
+
},
|
|
86
|
+
has(_target, prop) {
|
|
87
|
+
const outputs = _stepOutputsMap.get(stepName);
|
|
88
|
+
if (!outputs) return false;
|
|
89
|
+
return prop in outputs;
|
|
90
|
+
},
|
|
91
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
92
|
+
const outputs = _stepOutputsMap.get(stepName);
|
|
93
|
+
if (!outputs) return void 0;
|
|
94
|
+
if (prop in outputs) return {
|
|
95
|
+
configurable: true,
|
|
96
|
+
enumerable: true,
|
|
97
|
+
value: outputs[prop]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a Proxy over job outputs that resolves property access lazily
|
|
104
|
+
* against the module-global job outputs map.
|
|
105
|
+
*
|
|
106
|
+
* For multi-step jobs: job.result.stepName.field
|
|
107
|
+
* For single-step (run shorthand) jobs: job.result.field
|
|
108
|
+
*
|
|
109
|
+
* @param jobName - The name of the job whose outputs to proxy
|
|
110
|
+
* @returns A Proxy that resolves property access at runtime
|
|
111
|
+
*/
|
|
112
|
+
function createJobOutputProxy(jobName) {
|
|
113
|
+
return new Proxy({}, {
|
|
114
|
+
get(_target, prop, receiver) {
|
|
115
|
+
if (typeof prop === "symbol") return Reflect.get(_target, prop, receiver);
|
|
116
|
+
if (WELL_KNOWN_STRING_PROPS.has(prop)) return Reflect.get(_target, prop, receiver);
|
|
117
|
+
const outputs = _jobOutputsMap.get(jobName);
|
|
118
|
+
if (!outputs) throw new Error(`Job '${jobName}' has not produced outputs yet`);
|
|
119
|
+
return outputs[prop];
|
|
120
|
+
},
|
|
121
|
+
ownKeys() {
|
|
122
|
+
const outputs = _jobOutputsMap.get(jobName);
|
|
123
|
+
if (!outputs) return [];
|
|
124
|
+
return Reflect.ownKeys(outputs);
|
|
125
|
+
},
|
|
126
|
+
has(_target, prop) {
|
|
127
|
+
const outputs = _jobOutputsMap.get(jobName);
|
|
128
|
+
if (!outputs) return false;
|
|
129
|
+
return prop in outputs;
|
|
130
|
+
},
|
|
131
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
132
|
+
const outputs = _jobOutputsMap.get(jobName);
|
|
133
|
+
if (!outputs) return void 0;
|
|
134
|
+
if (prop in outputs) return {
|
|
135
|
+
configurable: true,
|
|
136
|
+
enumerable: true,
|
|
137
|
+
value: outputs[prop]
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Resolve step outputs by step reference (Step object or bare function).
|
|
144
|
+
* Used by ctx.outputsOf() implementation.
|
|
145
|
+
*
|
|
146
|
+
* @param ref - Step object (with _tag: 'Step') or bare function reference
|
|
147
|
+
* @param outputsMap - The outputs map to resolve against (defaults to module-global)
|
|
148
|
+
* @param refMap - The ref map for bare function -> name resolution (defaults to module-global)
|
|
149
|
+
* @returns The step's outputs
|
|
150
|
+
*/
|
|
151
|
+
function resolveStepOutputs(ref, outputsMap, refMap) {
|
|
152
|
+
const map = outputsMap ?? _stepOutputsMap;
|
|
153
|
+
const rMap = refMap ?? _stepRefMap;
|
|
154
|
+
let stepName;
|
|
155
|
+
if (typeof ref === "function") {
|
|
156
|
+
stepName = rMap.get(ref);
|
|
157
|
+
if (!stepName) throw new Error("Cannot resolve outputs for bare function: function not registered in step ref map");
|
|
158
|
+
} else if (ref && typeof ref === "object" && "_tag" in ref && ref._tag === "Step") stepName = ref.name;
|
|
159
|
+
else throw new Error("Invalid step reference: expected Step object or bare function");
|
|
160
|
+
const outputs = map.get(stepName);
|
|
161
|
+
if (!outputs) throw new Error(`Step '${stepName}' has not produced outputs yet`);
|
|
162
|
+
return outputs;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Resolve job outputs by job reference.
|
|
166
|
+
* Used by ctx.jobOutputs() implementation.
|
|
167
|
+
*
|
|
168
|
+
* @param ref - Job object reference (needs .name property)
|
|
169
|
+
* @param outputsMap - The outputs map to resolve against (defaults to module-global)
|
|
170
|
+
* @returns The job's outputs
|
|
171
|
+
*/
|
|
172
|
+
function resolveJobOutputs(ref, outputsMap) {
|
|
173
|
+
const outputs = (outputsMap ?? _jobOutputsMap).get(ref.name);
|
|
174
|
+
if (!outputs) throw new Error(`Job '${ref.name}' has not produced outputs yet`);
|
|
175
|
+
return outputs;
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
export { createJobOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap };
|
|
179
|
+
|
|
180
|
+
//# sourceMappingURL=outputs.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Rule, RuleContext, RuleResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Result of evaluating rules for a job or workflow.
|
|
4
|
+
* Contains overall pass/fail status and per-rule results.
|
|
5
|
+
*/
|
|
6
|
+
export interface RuleEvaluationResult {
|
|
7
|
+
allPassed: boolean;
|
|
8
|
+
results: RuleResult[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Evaluate rules sequentially with fail-fast behavior.
|
|
12
|
+
*
|
|
13
|
+
* Iterates rules in order, calling each rule's check function with the provided
|
|
14
|
+
* context. Records timing and result for each evaluated rule. Stops evaluation
|
|
15
|
+
* on the first failure (remaining rules are not evaluated).
|
|
16
|
+
*
|
|
17
|
+
* @param rules - Array of Rule objects to evaluate
|
|
18
|
+
* @param context - RuleContext providing event, env, changedFiles, and $
|
|
19
|
+
* @param _label - Human-readable label for logging (e.g., job name) -- reserved for callers
|
|
20
|
+
* @param onRuleResult - Optional callback invoked after each rule evaluation
|
|
21
|
+
* @returns RuleEvaluationResult with allPassed flag and per-rule results
|
|
22
|
+
*/
|
|
23
|
+
export declare function evaluateRules(rules: Rule[], context: RuleContext, _label: string, onRuleResult?: (result: RuleResult) => void): Promise<RuleEvaluationResult>;
|
|
24
|
+
//# sourceMappingURL=evaluator.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import "../chunk-gOLHoazu.js";
|
|
2
|
+
import { toErrorMessage } from "@kici-dev/shared";
|
|
3
|
+
//#region src/rules/evaluator.ts
|
|
4
|
+
/**
|
|
5
|
+
* Evaluate rules sequentially with fail-fast behavior.
|
|
6
|
+
*
|
|
7
|
+
* Iterates rules in order, calling each rule's check function with the provided
|
|
8
|
+
* context. Records timing and result for each evaluated rule. Stops evaluation
|
|
9
|
+
* on the first failure (remaining rules are not evaluated).
|
|
10
|
+
*
|
|
11
|
+
* @param rules - Array of Rule objects to evaluate
|
|
12
|
+
* @param context - RuleContext providing event, env, changedFiles, and $
|
|
13
|
+
* @param _label - Human-readable label for logging (e.g., job name) -- reserved for callers
|
|
14
|
+
* @param onRuleResult - Optional callback invoked after each rule evaluation
|
|
15
|
+
* @returns RuleEvaluationResult with allPassed flag and per-rule results
|
|
16
|
+
*/
|
|
17
|
+
async function evaluateRules(rules, context, _label, onRuleResult) {
|
|
18
|
+
const results = [];
|
|
19
|
+
let allPassed = true;
|
|
20
|
+
for (const rule of rules) {
|
|
21
|
+
const startTime = Date.now();
|
|
22
|
+
let passed = false;
|
|
23
|
+
let error;
|
|
24
|
+
try {
|
|
25
|
+
passed = await rule.check(context);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
passed = false;
|
|
28
|
+
error = toErrorMessage(e);
|
|
29
|
+
}
|
|
30
|
+
const durationMs = Date.now() - startTime;
|
|
31
|
+
const result = {
|
|
32
|
+
label: rule.label,
|
|
33
|
+
passed,
|
|
34
|
+
durationMs,
|
|
35
|
+
error
|
|
36
|
+
};
|
|
37
|
+
results.push(result);
|
|
38
|
+
onRuleResult?.(result);
|
|
39
|
+
if (!passed) {
|
|
40
|
+
allPassed = false;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
allPassed,
|
|
46
|
+
results
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
export { evaluateRules };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=evaluator.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { rule, skip } from './rule.js';
|
|
2
|
+
export { evaluateRules, type RuleEvaluationResult } from './evaluator.js';
|
|
3
|
+
export type { Rule, RuleCheckFn, RuleContext, RuleResult, EventPayload } from './types.js';
|
|
4
|
+
export { isEventType } from '../events/event-payloads.js';
|
|
5
|
+
export type { EventBase, PullRequestEventPayload, PushEventPayload, TagEventPayload, CommentEventPayload, ReviewEventPayload, ReviewCommentEventPayload, ReleaseEventPayload, DispatchEventPayload, CreateEventPayload, DeleteEventPayload, StatusEventPayload, WorkflowRunEventPayload, ForkEventPayload, StarEventPayload, WatchEventPayload, WebhookEventPayload, KiciEventPayload, WorkflowCompleteEventPayload, JobCompleteEventPayload, GenericWebhookEventPayload, ScheduleEventPayload, LifecycleEventPayload, GitHubRepository, GitHubUser, GitHubPullRequest, GitHubCommit, GitHubComment, GitHubReview, GitHubRelease, } from '../events/event-payloads.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Rule, RuleCheckFn } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create a rule with just a label (always passes).
|
|
4
|
+
* Useful for markers that appear in the decision trace.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* const marker = rule('ci: required check');
|
|
8
|
+
*/
|
|
9
|
+
export declare function rule(label: string): Rule;
|
|
10
|
+
/**
|
|
11
|
+
* Create a rule with a label and check function.
|
|
12
|
+
* The check function determines whether the rule passes.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const hasFrontend = rule('skip: no frontend changes', async (ctx) => {
|
|
16
|
+
* return ctx.changedFiles.some(f => f.startsWith('src/ui/'));
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export declare function rule(label: string, check: RuleCheckFn): Rule;
|
|
20
|
+
/**
|
|
21
|
+
* Create a rule that skips when the condition is met.
|
|
22
|
+
* Convenience wrapper around rule() that inverts the check function.
|
|
23
|
+
*
|
|
24
|
+
* When the check returns true (condition met), the rule returns false (skip).
|
|
25
|
+
* When the check returns false (condition not met), the rule returns true (run).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // Skip when PR only contains docs changes
|
|
29
|
+
* const skipDocsOnly = skip('docs only PR', async (ctx) => {
|
|
30
|
+
* return ctx.changedFiles.every(f => f.endsWith('.md'));
|
|
31
|
+
* });
|
|
32
|
+
*/
|
|
33
|
+
export declare function skip(label: string, check: RuleCheckFn): Rule;
|
|
34
|
+
//# sourceMappingURL=rule.d.ts.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import "../chunk-gOLHoazu.js";
|
|
2
|
+
//#region src/rules/rule.ts
|
|
3
|
+
/**
|
|
4
|
+
* Implementation of rule() factory.
|
|
5
|
+
* Creates a Rule with an optional check function (defaults to always-true).
|
|
6
|
+
*/
|
|
7
|
+
function rule(label, check) {
|
|
8
|
+
return {
|
|
9
|
+
_tag: "Rule",
|
|
10
|
+
label,
|
|
11
|
+
check: check ?? (() => true)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Create a rule that skips when the condition is met.
|
|
16
|
+
* Convenience wrapper around rule() that inverts the check function.
|
|
17
|
+
*
|
|
18
|
+
* When the check returns true (condition met), the rule returns false (skip).
|
|
19
|
+
* When the check returns false (condition not met), the rule returns true (run).
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // Skip when PR only contains docs changes
|
|
23
|
+
* const skipDocsOnly = skip('docs only PR', async (ctx) => {
|
|
24
|
+
* return ctx.changedFiles.every(f => f.endsWith('.md'));
|
|
25
|
+
* });
|
|
26
|
+
*/
|
|
27
|
+
function skip(label, check) {
|
|
28
|
+
return {
|
|
29
|
+
_tag: "Rule",
|
|
30
|
+
label,
|
|
31
|
+
check: async (ctx) => !await check(ctx)
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { rule, skip };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { $ as Shell } from 'zx';
|
|
2
|
+
import type { EventPayload } from '../events/event-payloads.js';
|
|
3
|
+
export type { EventPayload } from '../events/event-payloads.js';
|
|
4
|
+
/**
|
|
5
|
+
* Context passed to rule check functions.
|
|
6
|
+
* Provides access to event data, changed files, environment, and shell execution.
|
|
7
|
+
*/
|
|
8
|
+
export interface RuleContext {
|
|
9
|
+
/** The triggering event payload */
|
|
10
|
+
event: EventPayload;
|
|
11
|
+
/** List of files changed in this event (e.g., PR diff) */
|
|
12
|
+
changedFiles: string[];
|
|
13
|
+
/** Environment variables */
|
|
14
|
+
env: Record<string, string | undefined>;
|
|
15
|
+
/** zx shell executor for running commands */
|
|
16
|
+
$: typeof Shell;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Function type for rule check functions.
|
|
20
|
+
* Can be sync or async - returns whether the rule passes.
|
|
21
|
+
*/
|
|
22
|
+
export type RuleCheckFn = (ctx: RuleContext) => Promise<boolean> | boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Rule definition returned by rule() factory.
|
|
25
|
+
* Rules are labeled conditional checks that appear in the decision trace.
|
|
26
|
+
*/
|
|
27
|
+
export interface Rule {
|
|
28
|
+
readonly _tag: 'Rule';
|
|
29
|
+
readonly label: string;
|
|
30
|
+
readonly check: RuleCheckFn;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Result of evaluating a rule (for decision trace).
|
|
34
|
+
* Records whether the rule passed and how long evaluation took.
|
|
35
|
+
*/
|
|
36
|
+
export interface RuleResult {
|
|
37
|
+
label: string;
|
|
38
|
+
passed: boolean;
|
|
39
|
+
durationMs: number;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata about a resolved secret -- which backend and scope provided it.
|
|
3
|
+
*/
|
|
4
|
+
export interface SecretMeta {
|
|
5
|
+
/** The resolved secret value. */
|
|
6
|
+
value: string;
|
|
7
|
+
/** Backend name that provided the secret (e.g., 'pg', 'openbao-stg'). */
|
|
8
|
+
backend: string;
|
|
9
|
+
/** Full prefixed scope path (e.g., 'pg:production/db'). */
|
|
10
|
+
scope: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Options for materialising one or more existing secret values as a file
|
|
14
|
+
* on-disk inside the per-step tmpdir.
|
|
15
|
+
*/
|
|
16
|
+
export interface SecretFileOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Names of existing secret keys to concatenate (in order) into the file.
|
|
19
|
+
* Each key must resolve via `ctx.secrets.get(key)`; missing keys cause
|
|
20
|
+
* `SecretNotFoundError` to be thrown (carrying every missing key).
|
|
21
|
+
*/
|
|
22
|
+
sources: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Optional separator written between concatenated source values.
|
|
25
|
+
* Default: no divider (values are joined back-to-back).
|
|
26
|
+
*/
|
|
27
|
+
divider?: string;
|
|
28
|
+
/**
|
|
29
|
+
* File mode to chmod the materialised file to. Default `0o600`
|
|
30
|
+
* (owner read/write only).
|
|
31
|
+
*/
|
|
32
|
+
mode?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Optional filename inside the per-step tmpdir. When omitted, the
|
|
35
|
+
* runtime auto-generates a unique name (`secret-1`, `secret-2`, ...).
|
|
36
|
+
*/
|
|
37
|
+
name?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Result of a `mountFile` / `exposeFile` call.
|
|
41
|
+
*/
|
|
42
|
+
export interface MountedFile {
|
|
43
|
+
/** Absolute path to the materialised file inside the per-step tmpdir. */
|
|
44
|
+
path: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Host-side adapter passed by the agent to back the file-mount API.
|
|
48
|
+
*
|
|
49
|
+
* The SDK owns the public surface (`mountFile` / `exposeFile`) but defers
|
|
50
|
+
* disk and `process.env` operations to the agent so the SDK stays free of
|
|
51
|
+
* any `node:fs` / `node:os` imports. Local-test mode (`kici test`) plugs
|
|
52
|
+
* in the same adapter shape against `os.tmpdir()`.
|
|
53
|
+
*/
|
|
54
|
+
export interface StepSecretsFileHost {
|
|
55
|
+
/**
|
|
56
|
+
* Materialise the concatenated content to a file inside the per-step
|
|
57
|
+
* tmpdir. The host is responsible for chmod + masker registration
|
|
58
|
+
* (when applicable) and for remembering the file for cleanup.
|
|
59
|
+
* Returns the absolute path on success.
|
|
60
|
+
*/
|
|
61
|
+
writeMountedFile(args: {
|
|
62
|
+
content: string;
|
|
63
|
+
sources: string[];
|
|
64
|
+
mode: number;
|
|
65
|
+
name?: string;
|
|
66
|
+
}): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Track an env var that was set as part of `exposeFile`, so the
|
|
69
|
+
* runtime can `delete process.env[envVar]` during `dispose()`.
|
|
70
|
+
*/
|
|
71
|
+
trackExposedEnv(envVar: string): void;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Async accessor interface for step secrets.
|
|
75
|
+
* Secrets are never automatically injected into environment variables.
|
|
76
|
+
* Use get() to read a secret value, expose() to explicitly inject into env.
|
|
77
|
+
*/
|
|
78
|
+
export interface StepSecrets {
|
|
79
|
+
/** Retrieve a secret value by key. Rejects with SecretNotFoundError if not found. */
|
|
80
|
+
get(key: string): Promise<string>;
|
|
81
|
+
/** Inject a secret into the step's environment variables. Rejects if key not found. */
|
|
82
|
+
expose(key: string): Promise<void>;
|
|
83
|
+
/** Check if a secret key exists. Synchronous, never throws. */
|
|
84
|
+
has(key: string): boolean;
|
|
85
|
+
/** Retrieve metadata about a resolved secret (backend name and scope). Returns undefined if key not found. */
|
|
86
|
+
getMeta(key: string): SecretMeta | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Return every secret key available to this step, sorted alphabetically.
|
|
89
|
+
* Synchronous, never throws. Returns names only -- call `getMeta(key)` to
|
|
90
|
+
* inspect backend / scope for a specific key.
|
|
91
|
+
*/
|
|
92
|
+
list(): string[];
|
|
93
|
+
/**
|
|
94
|
+
* Materialise one or more existing secrets as a tmpfile inside a
|
|
95
|
+
* per-step tmpdir. Returns the absolute file path. The file is removed
|
|
96
|
+
* automatically when the step completes (success, failure, or timeout).
|
|
97
|
+
* Rejects with `SecretNotFoundError` if any source key is missing.
|
|
98
|
+
*/
|
|
99
|
+
mountFile(opts: SecretFileOptions): Promise<MountedFile>;
|
|
100
|
+
/**
|
|
101
|
+
* Sugar: call `mountFile(opts)`, then set `process.env[envVar]` to the
|
|
102
|
+
* resulting path. The env var is unset and the file is removed when
|
|
103
|
+
* the step completes.
|
|
104
|
+
*/
|
|
105
|
+
exposeFile(envVar: string, opts: SecretFileOptions): Promise<MountedFile>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Extended StepSecrets with access tracking.
|
|
109
|
+
* Tracks which secret keys were accessed via get() or expose() calls.
|
|
110
|
+
* Only key names are recorded -- never values.
|
|
111
|
+
*/
|
|
112
|
+
export interface TrackedStepSecrets extends StepSecrets {
|
|
113
|
+
/** Returns sorted array of secret key names accessed via get() or expose(). */
|
|
114
|
+
getAccessLog(): string[];
|
|
115
|
+
/**
|
|
116
|
+
* Returns sorted array of secret key names referenced via `mountFile()` /
|
|
117
|
+
* `exposeFile()`. Mounts are tracked separately from plain `get` / `expose`
|
|
118
|
+
* accesses so the orchestrator can render a distinct audit row.
|
|
119
|
+
*/
|
|
120
|
+
getMountedKeys(): string[];
|
|
121
|
+
/**
|
|
122
|
+
* Returns the audit records of every mount call (in order). Used by the
|
|
123
|
+
* agent to emit `step.secret_mount` IPC events. Each record carries
|
|
124
|
+
* `{ sources, target, envVar?, kind }`. `target` is the absolute path the
|
|
125
|
+
* file was materialised to.
|
|
126
|
+
*/
|
|
127
|
+
getMountRecords(): readonly StepSecretMountRecord[];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Kinds of secret-file materialisation operations. Surfaced as the `kind`
|
|
131
|
+
* discriminator on the IPC event so the orchestrator can distinguish a
|
|
132
|
+
* plain mount from a mount-with-env-var binding.
|
|
133
|
+
*/
|
|
134
|
+
export type StepSecretMountKind = 'mountFile' | 'exposeFile';
|
|
135
|
+
/**
|
|
136
|
+
* Audit record for a single secret-file materialisation operation.
|
|
137
|
+
* Never contains the file content -- only the key names and the
|
|
138
|
+
* resulting path / env var.
|
|
139
|
+
*/
|
|
140
|
+
export interface StepSecretMountRecord {
|
|
141
|
+
/** Source secret keys (in concatenation order). */
|
|
142
|
+
sources: string[];
|
|
143
|
+
/** Absolute path the file was materialised to. */
|
|
144
|
+
target: string;
|
|
145
|
+
/** Env var set when `kind === 'exposeFile'`; otherwise undefined. */
|
|
146
|
+
envVar?: string;
|
|
147
|
+
/** Discriminator between `mountFile` and `exposeFile`. */
|
|
148
|
+
kind: StepSecretMountKind;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Result of {@link createStepSecrets}: the secrets surface itself plus a
|
|
152
|
+
* `dispose` callback the agent invokes from the step-loop `finally` to
|
|
153
|
+
* remove materialised files and clear any exposed env vars.
|
|
154
|
+
*
|
|
155
|
+
* `dispose` swallows its own errors -- it never throws. Failures are
|
|
156
|
+
* surfaced via the optional `onDisposeError` callback passed when the
|
|
157
|
+
* file-mount host was wired in.
|
|
158
|
+
*/
|
|
159
|
+
export interface StepSecretsHandle {
|
|
160
|
+
/** The secrets surface bound into `ctx.secrets`. */
|
|
161
|
+
secrets: TrackedStepSecrets;
|
|
162
|
+
/** Tear down any materialised files and unset exposed env vars. */
|
|
163
|
+
dispose: () => Promise<void>;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Optional wiring for the file-mount + cleanup path. When omitted, calls
|
|
167
|
+
* to `mountFile` / `exposeFile` throw -- the SDK alone cannot mount files
|
|
168
|
+
* (no `node:fs` dependency). Production wires a host implementation in
|
|
169
|
+
* the agent; local test mode wires a minimal `os.tmpdir`-backed host.
|
|
170
|
+
*/
|
|
171
|
+
export interface StepSecretsFileWiring {
|
|
172
|
+
/** The host adapter (see {@link StepSecretsFileHost}). */
|
|
173
|
+
host: StepSecretsFileHost;
|
|
174
|
+
/** Callback for `dispose()` errors. Receives the error for logging. */
|
|
175
|
+
onDisposeError?: (err: unknown) => void;
|
|
176
|
+
/** Tear down callback invoked by `dispose()` (removes the tmpdir, etc.). */
|
|
177
|
+
cleanup: () => Promise<void>;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Create a StepSecrets instance backed by a plain secrets map.
|
|
181
|
+
* The env parameter receives exposed secrets via expose().
|
|
182
|
+
* Tracks which secrets are accessed for audit/observability purposes.
|
|
183
|
+
*
|
|
184
|
+
* @param secretsMap - Flat key-value secrets map
|
|
185
|
+
* @param env - Process environment to inject exposed secrets into
|
|
186
|
+
* @param metaMap - Optional metadata map from resolveForJobWithMeta (backend + scope per key)
|
|
187
|
+
* @param fileWiring - Optional file-mount host adapter. When omitted, `mountFile`
|
|
188
|
+
* and `exposeFile` throw -- callers that don't wire a host can still use the
|
|
189
|
+
* string-only `get` / `expose` / `has` / `list` surface.
|
|
190
|
+
*/
|
|
191
|
+
export declare function createStepSecrets(secretsMap: Record<string, string>, env: Record<string, string | undefined>, metaMap?: Record<string, SecretMeta>, fileWiring?: StepSecretsFileWiring): StepSecretsHandle;
|
|
192
|
+
//# sourceMappingURL=secrets.d.ts.map
|