@kici-dev/compiler 0.1.16 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/headless-detect.js +1 -1
- package/dist/cli-banner.js +1 -1
- package/dist/cli.js +56 -19
- package/dist/commands/approve.js +1 -1
- package/dist/commands/compile.js +5 -3
- package/dist/commands/diagnostics.d.ts +7 -0
- package/dist/commands/diagnostics.js +58 -0
- package/dist/commands/docs.js +1 -1
- package/dist/commands/drain-worker.js +1 -1
- package/dist/commands/endpoints.js +1 -1
- package/dist/commands/fixture.js +1 -1
- package/dist/commands/held-run-client.js +1 -1
- package/dist/commands/held-run-resolve.js +1 -1
- package/dist/commands/hook.js +1 -1
- package/dist/commands/index.d.ts +16 -4
- package/dist/commands/index.js +10 -4
- package/dist/commands/init.js +2 -2
- package/dist/commands/login.d.ts +0 -2
- package/dist/commands/login.js +1 -3
- package/dist/commands/logout.js +1 -1
- package/dist/commands/orchestrators.d.ts +25 -0
- package/dist/commands/orchestrators.js +115 -0
- package/dist/commands/org.js +1 -1
- package/dist/commands/reject.js +1 -1
- package/dist/commands/run.d.ts +2 -9
- package/dist/commands/run.js +256 -315
- package/dist/commands/runs/cancel.d.ts +6 -0
- package/dist/commands/runs/cancel.js +32 -0
- package/dist/commands/runs/list.d.ts +6 -0
- package/dist/commands/runs/list.js +49 -0
- package/dist/commands/runs/logs.d.ts +7 -0
- package/dist/commands/runs/logs.js +67 -0
- package/dist/commands/runs/rerun.d.ts +5 -0
- package/dist/commands/runs/rerun.js +21 -0
- package/dist/commands/runs/show.d.ts +5 -0
- package/dist/commands/runs/show.js +65 -0
- package/dist/commands/secrets-list.d.ts +7 -9
- package/dist/commands/secrets-list.js +40 -64
- package/dist/commands/test.d.ts +4 -0
- package/dist/commands/test.js +1 -1
- package/dist/commands/types.d.ts +3 -5
- package/dist/commands/types.js +13 -37
- package/dist/commands/verify-attestation.d.ts +12 -0
- package/dist/commands/verify-attestation.js +69 -0
- package/dist/commands/watch.js +1 -1
- package/dist/commands/workflows.js +14 -34
- package/dist/errors/capability-gap.js +1 -1
- package/dist/errors/formatter.js +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/execution/executor.js +1 -1
- package/dist/execution/index.js +1 -1
- package/dist/execution/sdk-alias.js +1 -1
- package/dist/execution/ts-loader.js +1 -1
- package/dist/fixtures/compiler.js +1 -1
- package/dist/fixtures/defaults/index.js +1 -1
- package/dist/format.js +1 -1
- package/dist/generators/secrets-dts.js +2 -2
- package/dist/hooks/detector.js +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/installer.js +1 -1
- package/dist/hooks/templates.js +1 -1
- package/dist/index.js +1 -1
- package/dist/llm-context/llms-full.txt +1047 -132
- package/dist/llm-context/llms.txt +4 -1
- package/dist/local-executor/dag-scheduler.js +1 -1
- package/dist/local-executor/index.js +1 -1
- package/dist/local-executor/job-runner.js +37 -16
- package/dist/local-executor/materializer.js +1 -1
- package/dist/local-executor/output-streamer.js +1 -1
- package/dist/local-executor/payload-generator.js +1 -1
- package/dist/local-executor/picker.js +1 -1
- package/dist/local-executor/secret-loader.js +1 -1
- package/dist/local-executor/to-event-payload.js +1 -1
- package/dist/local-executor/types.js +1 -1
- package/dist/local-executor/workflow-lock.js +0 -0
- package/dist/lockfile/generator.d.ts +7 -5
- package/dist/lockfile/generator.js +21 -18
- package/dist/lockfile/hash-files.js +1 -1
- package/dist/lockfile/hasher.js +1 -1
- package/dist/lockfile/index.js +1 -1
- package/dist/lockfile/purity-analyzer.js +1 -1
- package/dist/postinstall.js +1 -1
- package/dist/provenance-trust-root.d.ts +14 -0
- package/dist/provenance-trust-root.js +49 -0
- package/dist/remote/config.d.ts +6 -2
- package/dist/remote/config.js +7 -4
- package/dist/remote/dashboard-client.d.ts +92 -0
- package/dist/remote/dashboard-client.js +168 -0
- package/dist/remote/encryption.js +3 -4
- package/dist/remote/history.js +1 -1
- package/dist/remote/oauth.js +1 -1
- package/dist/remote/oidc-discovery.js +1 -1
- package/dist/remote/output/json.js +1 -1
- package/dist/remote/output/junit.js +1 -1
- package/dist/remote/output/streaming.js +1 -1
- package/dist/remote/output/summary.js +1 -1
- package/dist/remote/platform-client.d.ts +142 -0
- package/dist/remote/platform-client.js +187 -0
- package/dist/remote/prod-defaults.js +1 -1
- package/dist/remote/render.d.ts +11 -0
- package/dist/remote/render.js +48 -0
- package/dist/remote/secret-upload.js +1 -1
- package/dist/remote/uploader.d.ts +9 -0
- package/dist/remote/uploader.js +51 -4
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +8 -3
- package/dist/templates/index.js +1 -1
- package/dist/templates/package-json.js +4 -5
- package/dist/templates/tsconfig-json.js +1 -1
- package/dist/templates/workflows/hello-world.js +2 -2
- package/dist/templates/workflows/hello-world.ts +1 -1
- package/dist/templates/workflows/pr-checks.js +3 -3
- package/dist/templates/workflows/pr-checks.ts +2 -2
- package/dist/test-runner/dry-run.js +1 -1
- package/dist/test-runner/event-types.js +1 -1
- package/dist/test-runner/git-detector.js +1 -1
- package/dist/test-runner/index.js +1 -1
- package/dist/test-runner/job-executor.js +1 -1
- package/dist/test-runner/output-formatter.js +1 -1
- package/dist/test-runner/payload-builder.js +1 -1
- package/dist/test-runner/rule-evaluator.js +1 -1
- package/dist/test-runner/secrets-file.js +1 -1
- package/dist/test-runner/step-context.js +10 -6
- package/dist/types.d.ts +8 -5
- package/dist/types.js +2 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/validator.js +1 -1
- package/dist/workflows/hello-world.ts +1 -1
- package/dist/workflows/pr-checks.ts +2 -2
- package/package.json +5 -4
- package/sbom.spdx.json +68 -38
- package/dist/commands/cancel.js +0 -124
- package/dist/commands/status.js +0 -212
- package/dist/remote/client.js +0 -203
- package/dist/remote/observer.js +0 -174
- /package/dist/{chunk-gOLHoazu.js → chunk-BTugEXQM.js} +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "../../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../../remote/dashboard-client.js";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
5
|
+
//#region src/commands/runs/cancel.ts
|
|
6
|
+
/** kici runs cancel — cancel a run or all in-progress runs on a branch. */
|
|
7
|
+
async function runsCancelCommand(runId, options = {}) {
|
|
8
|
+
try {
|
|
9
|
+
const client = await DashboardClient.load();
|
|
10
|
+
if (options.branch) {
|
|
11
|
+
logger.info(`Cancelling all in-progress runs on branch ${pc.cyan(options.branch)}...`);
|
|
12
|
+
const { cancelledRuns = 0 } = await client.cancelByBranch(options.branch);
|
|
13
|
+
console.log(cancelledRuns === 0 ? pc.yellow(`No in-progress runs found on branch ${options.branch}.`) : pc.green(`Cancelled ${cancelledRuns} run${cancelledRuns !== 1 ? "s" : ""} on branch ${options.branch}.`));
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
if (!runId) {
|
|
17
|
+
logger.error(pc.red("Please provide a run ID or use --branch to cancel by branch."));
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
logger.info(`${options.force ? "Force-cancelling" : "Cancelling"} run ${pc.cyan(runId)}...`);
|
|
21
|
+
const { cancelledJobs = 0 } = await client.cancelRun(runId, options.force ?? false);
|
|
22
|
+
console.log(pc.green(`Run ${runId} cancelled (${cancelledJobs} job${cancelledJobs !== 1 ? "s" : ""} affected).`));
|
|
23
|
+
return true;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { runsCancelCommand };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=cancel.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type RunsListFilters } from '../../remote/dashboard-client.js';
|
|
2
|
+
export interface RunsListOptions extends RunsListFilters {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export declare function runsListCommand(options?: RunsListOptions): Promise<boolean>;
|
|
6
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import "../../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../../remote/dashboard-client.js";
|
|
3
|
+
import { colorStatus, formatDuration as formatDuration$1, relativeTime, renderTable } from "../../remote/render.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
//#region src/commands/runs/list.ts
|
|
7
|
+
/** kici runs list — mirrors the dashboard Runs page list. */
|
|
8
|
+
async function runsListCommand(options = {}) {
|
|
9
|
+
try {
|
|
10
|
+
const client = await DashboardClient.load();
|
|
11
|
+
const { json, ...filters } = options;
|
|
12
|
+
const page = await client.listRuns(filters);
|
|
13
|
+
if (json) {
|
|
14
|
+
console.log(JSON.stringify(page, null, 2));
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (page.runs.length === 0) {
|
|
18
|
+
console.log(pc.gray("No runs found."));
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const rows = page.runs.map((r) => [
|
|
22
|
+
r.runId,
|
|
23
|
+
r.workflowName ?? "—",
|
|
24
|
+
colorStatus(r.status),
|
|
25
|
+
r.ref ?? "—",
|
|
26
|
+
r.triggerEvent ?? "—",
|
|
27
|
+
relativeTime(r.startedAt ?? void 0),
|
|
28
|
+
r.durationMs ? formatDuration$1(r.durationMs) : "—"
|
|
29
|
+
]);
|
|
30
|
+
console.log(renderTable([
|
|
31
|
+
"run-id",
|
|
32
|
+
"workflow",
|
|
33
|
+
"status",
|
|
34
|
+
"branch",
|
|
35
|
+
"trigger",
|
|
36
|
+
"started",
|
|
37
|
+
"duration"
|
|
38
|
+
], rows));
|
|
39
|
+
console.log(pc.gray(`\nPage ${page.page} · ${page.runs.length} of ${page.total}${page.hasMore ? " (more — use --page)" : ""}`));
|
|
40
|
+
return true;
|
|
41
|
+
} catch (err) {
|
|
42
|
+
logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//#endregion
|
|
47
|
+
export { runsListCommand };
|
|
48
|
+
|
|
49
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import "../../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../../remote/dashboard-client.js";
|
|
3
|
+
import { colorStatus } from "../../remote/render.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
import { TERMINAL_RUN_STATES } from "@kici-dev/engine";
|
|
7
|
+
//#region src/commands/runs/logs.ts
|
|
8
|
+
/** kici runs logs — step logs for a run (replaces `kici status --logs`). */
|
|
9
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
10
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
11
|
+
async function runsLogsCommand(runId, options = {}) {
|
|
12
|
+
try {
|
|
13
|
+
const client = await DashboardClient.load();
|
|
14
|
+
if (options.json) {
|
|
15
|
+
const out = await collectAllLogs(client, runId, (await client.getRunDetail(runId)).jobs, options.job);
|
|
16
|
+
console.log(JSON.stringify(out, null, 2));
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
if (options.follow) return await followLogs(client, runId, options.job);
|
|
20
|
+
await printAllLogs(client, runId, (await client.getRunDetail(runId)).jobs, options.job);
|
|
21
|
+
return true;
|
|
22
|
+
} catch (err) {
|
|
23
|
+
logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function selectJobs(jobs, jobFilter) {
|
|
28
|
+
return jobFilter ? jobs.filter((j) => j.jobName === jobFilter) : jobs;
|
|
29
|
+
}
|
|
30
|
+
async function printAllLogs(client, runId, jobs, jobFilter) {
|
|
31
|
+
for (const j of selectJobs(jobs, jobFilter)) for (const s of j.steps ?? []) {
|
|
32
|
+
console.log(pc.bold(`\n=== ${j.jobName} › ${s.stepName} `) + colorStatus(s.status) + pc.bold(" ==="));
|
|
33
|
+
const logs = await client.getStepLogs(runId, j.jobId, s.stepIndex);
|
|
34
|
+
for (const line of logs.lines) console.log(line);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function collectAllLogs(client, runId, jobs, jobFilter) {
|
|
38
|
+
const out = {};
|
|
39
|
+
for (const j of selectJobs(jobs, jobFilter)) for (const s of j.steps ?? []) out[`${j.jobName}/${s.stepName}`] = (await client.getStepLogs(runId, j.jobId, s.stepIndex)).lines;
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
async function followLogs(client, runId, jobFilter) {
|
|
43
|
+
const printed = {};
|
|
44
|
+
for (;;) {
|
|
45
|
+
const run = await client.getRun(runId);
|
|
46
|
+
const detail = await client.getRunDetail(runId);
|
|
47
|
+
for (const j of selectJobs(detail.jobs, jobFilter)) for (const s of j.steps ?? []) {
|
|
48
|
+
const key = `${j.jobId}:${s.stepIndex}`;
|
|
49
|
+
const logs = await client.getStepLogs(runId, j.jobId, s.stepIndex);
|
|
50
|
+
const seen = printed[key] ?? 0;
|
|
51
|
+
if (logs.lines.length > seen) {
|
|
52
|
+
if (seen === 0) console.log(pc.bold(`\n=== ${j.jobName} › ${s.stepName} ===`));
|
|
53
|
+
for (const line of logs.lines.slice(seen)) console.log(line);
|
|
54
|
+
printed[key] = logs.lines.length;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (TERMINAL_RUN_STATES.has(run.status)) {
|
|
58
|
+
console.log(pc.gray(`\nrun ${colorStatus(run.status)}`));
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
await sleep(POLL_INTERVAL_MS);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { runsLogsCommand };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=logs.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import "../../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../../remote/dashboard-client.js";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
5
|
+
//#region src/commands/runs/rerun.ts
|
|
6
|
+
/** kici runs rerun — re-trigger a run (mirrors the dashboard rerun button). */
|
|
7
|
+
async function runsRerunCommand(runId, options = {}) {
|
|
8
|
+
try {
|
|
9
|
+
const out = await (await DashboardClient.load()).rerunRun(runId);
|
|
10
|
+
if (options.json) console.log(JSON.stringify(out, null, 2));
|
|
11
|
+
else console.log(pc.green(`Rerun queued: ${pc.bold(out.newRunId)}`));
|
|
12
|
+
return true;
|
|
13
|
+
} catch (err) {
|
|
14
|
+
logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { runsRerunCommand };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=rerun.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import "../../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../../remote/dashboard-client.js";
|
|
3
|
+
import { RunHistory } from "../../remote/history.js";
|
|
4
|
+
import { colorStatus, formatDuration as formatDuration$1, relativeTime } from "../../remote/render.js";
|
|
5
|
+
import pc from "picocolors";
|
|
6
|
+
import { logger, toErrorMessage } from "@kici-dev/core";
|
|
7
|
+
//#region src/commands/runs/show.ts
|
|
8
|
+
/** kici runs show — run summary + jobs/steps tree (replaces `kici status`). */
|
|
9
|
+
async function runsShowCommand(runId, options = {}) {
|
|
10
|
+
try {
|
|
11
|
+
const client = await DashboardClient.load();
|
|
12
|
+
let run;
|
|
13
|
+
try {
|
|
14
|
+
run = await client.getRun(runId);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
if (err instanceof DashboardClientError && err.kind === "not_found") return await showLocalFallback(runId, options.json ?? false);
|
|
17
|
+
throw err;
|
|
18
|
+
}
|
|
19
|
+
const detail = await client.getRunDetail(runId);
|
|
20
|
+
if (options.json) {
|
|
21
|
+
console.log(JSON.stringify({
|
|
22
|
+
run,
|
|
23
|
+
detail
|
|
24
|
+
}, null, 2));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
printHeader(run);
|
|
28
|
+
printJobs(detail.jobs);
|
|
29
|
+
return true;
|
|
30
|
+
} catch (err) {
|
|
31
|
+
logger.error(pc.red(err instanceof DashboardClientError ? err.message : toErrorMessage(err)));
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function printHeader(run) {
|
|
36
|
+
const f = (v) => v == null ? "—" : v;
|
|
37
|
+
console.log(pc.bold(`\nRun ${run.runId}`) + ` ${colorStatus(run.status)}`);
|
|
38
|
+
console.log(pc.gray(` workflow=${f(run.workflowName)} repo=${f(run.repoIdentifier)} branch=${f(run.ref)} sha=${f(run.sha)} trigger=${f(run.triggerEvent)} by=${f(run.triggeredBy)}`));
|
|
39
|
+
console.log(pc.gray(` started=${relativeTime(run.startedAt ?? void 0)}`));
|
|
40
|
+
}
|
|
41
|
+
function printJobs(jobs) {
|
|
42
|
+
for (const j of jobs) {
|
|
43
|
+
console.log(`\n ${pc.bold(j.jobName)} ${colorStatus(j.status)} ` + pc.gray(j.durationMs ? formatDuration$1(j.durationMs) : ""));
|
|
44
|
+
for (const s of j.steps ?? []) console.log(pc.gray(" └─ ") + `${s.stepName} ${colorStatus(s.status)} ` + pc.gray(`${s.durationMs ? formatDuration$1(s.durationMs) : ""}${s.exitCode != null ? ` exit=${s.exitCode}` : ""}`));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function showLocalFallback(runId, json) {
|
|
48
|
+
const history = new RunHistory();
|
|
49
|
+
await history.load();
|
|
50
|
+
const entry = history.getEntry(runId);
|
|
51
|
+
if (!entry) {
|
|
52
|
+
logger.error(pc.red(`Run not found: ${runId} (no remote run and no local history).`));
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
if (json) console.log(JSON.stringify(entry, null, 2));
|
|
56
|
+
else {
|
|
57
|
+
logger.info(pc.yellow("Run not found on the Platform. Showing local history:\n"));
|
|
58
|
+
console.log(JSON.stringify(entry, null, 2));
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { runsShowCommand };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
export interface SecretsListOptions {
|
|
2
|
-
/**
|
|
2
|
+
/** Reserved for future use; the command targets the Platform via the active org. */
|
|
3
3
|
endpoint?: string;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* List test-available secret contexts
|
|
6
|
+
* List test-available secret contexts through the Platform.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Values are never exposed -- only key names.
|
|
8
|
+
* Calls GET /api/v1/orgs/:orgId/environments?includeSecrets=true (relayed to
|
|
9
|
+
* the org's orchestrator), filters to environments with
|
|
10
|
+
* allowLocalExecution=true, and displays a table of names, key names, and
|
|
11
|
+
* flags. Values are never exposed -- only key names.
|
|
14
12
|
*/
|
|
15
|
-
export declare function secretsListCommand(
|
|
13
|
+
export declare function secretsListCommand(_options?: SecretsListOptions): Promise<boolean>;
|
|
16
14
|
//# sourceMappingURL=secrets-list.d.ts.map
|
|
@@ -1,84 +1,60 @@
|
|
|
1
|
-
import "../chunk-
|
|
2
|
-
import {
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { DashboardClient, DashboardClientError } from "../remote/dashboard-client.js";
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
import { toErrorMessage } from "@kici-dev/core";
|
|
5
5
|
//#region src/commands/secrets-list.ts
|
|
6
6
|
/**
|
|
7
|
-
* List test-available secret contexts
|
|
7
|
+
* List test-available secret contexts through the Platform.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* Values are never exposed -- only key names.
|
|
9
|
+
* Calls GET /api/v1/orgs/:orgId/environments?includeSecrets=true (relayed to
|
|
10
|
+
* the org's orchestrator), filters to environments with
|
|
11
|
+
* allowLocalExecution=true, and displays a table of names, key names, and
|
|
12
|
+
* flags. Values are never exposed -- only key names.
|
|
15
13
|
*/
|
|
16
|
-
async function secretsListCommand(
|
|
14
|
+
async function secretsListCommand(_options = {}) {
|
|
17
15
|
try {
|
|
18
|
-
const
|
|
19
|
-
if (!config.token) {
|
|
20
|
-
console.error(pc.red("Not authenticated. Run `kici login` first."));
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
const endpoint = options.endpoint ?? config.endpoint;
|
|
24
|
-
if (!endpoint) {
|
|
25
|
-
console.error(pc.red("No orchestrator endpoint configured. Run `kici login --endpoint <url>` first."));
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
if (!config.activeOrgId) {
|
|
29
|
-
console.error(pc.red("No active organization. Run `kici org list` then `kici org use <name>` first."));
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const url = `${endpoint.replace(/\/+$/, "")}/api/v1/admin/environments?orgId=${encodeURIComponent(config.activeOrgId)}&includeSecrets=true`;
|
|
33
|
-
const res = await fetch(url, { headers: { Authorization: `Bearer ${config.token}` } });
|
|
34
|
-
if (res.status === 401) {
|
|
35
|
-
console.error(pc.red("Authentication failed. Check your API key with `kici login`."));
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
if (res.status === 403) {
|
|
39
|
-
console.error(pc.red("Permission denied. Your API key does not have secret.read access."));
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
if (!res.ok) {
|
|
43
|
-
const text = await res.text();
|
|
44
|
-
console.error(pc.red(`Failed to fetch contexts: ${res.status} ${text}`));
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
const contexts = ((await res.json()).environments ?? []).filter((e) => e.allow_local_execution);
|
|
16
|
+
const contexts = (await (await DashboardClient.load()).listEnvironments(true)).filter((e) => e.allowLocalExecution);
|
|
48
17
|
if (contexts.length === 0) {
|
|
49
18
|
console.log(pc.yellow("No test-available secret contexts found."));
|
|
50
19
|
console.log(pc.gray("Enable test runs (allowLocalExecution) on an environment to make its secrets available for test runs."));
|
|
51
20
|
return true;
|
|
52
21
|
}
|
|
53
|
-
|
|
54
|
-
const ctxKeys = (c) => c.secret_keys ?? [];
|
|
55
|
-
const nameWidth = Math.max(7, ...contexts.map((c) => c.name.length));
|
|
56
|
-
const keysWidth = Math.max(4, ...contexts.map((c) => {
|
|
57
|
-
const k = ctxKeys(c);
|
|
58
|
-
return k.length > 0 ? k.join(", ").length : 4;
|
|
59
|
-
}));
|
|
60
|
-
const flagsWidth = Math.max(5, ...contexts.map((c) => c.enabled ? 0 : 8));
|
|
61
|
-
const pad = (s, w) => s.padEnd(w);
|
|
62
|
-
const hr = (w) => "─".repeat(w);
|
|
63
|
-
console.log(`\u250c${hr(nameWidth + 2)}\u252c${hr(keysWidth + 2)}\u252c${hr(flagsWidth + 2)}\u2510`);
|
|
64
|
-
console.log(`\u2502 ${pad("Context", nameWidth)} \u2502 ${pad("Keys", keysWidth)} \u2502 ${pad("Flags", flagsWidth)} \u2502`);
|
|
65
|
-
console.log(`\u251c${hr(nameWidth + 2)}\u253c${hr(keysWidth + 2)}\u253c${hr(flagsWidth + 2)}\u2524`);
|
|
66
|
-
for (const ctx of contexts) {
|
|
67
|
-
const k = ctxKeys(ctx);
|
|
68
|
-
const keys = k.length > 0 ? k.join(", ") : pc.gray("none");
|
|
69
|
-
const keysRaw = k.length > 0 ? k.join(", ") : "none";
|
|
70
|
-
const flagStr = ctx.enabled ? "" : "disabled";
|
|
71
|
-
console.log(`\u2502 ${pad(ctx.name, nameWidth)} \u2502 ${keys}${" ".repeat(Math.max(0, keysWidth - keysRaw.length))} \u2502 ${pad(flagStr, flagsWidth)} \u2502`);
|
|
72
|
-
}
|
|
73
|
-
console.log(`\u2514${hr(nameWidth + 2)}\u2534${hr(keysWidth + 2)}\u2534${hr(flagsWidth + 2)}\u2518`);
|
|
74
|
-
console.log("");
|
|
22
|
+
renderContextTable(contexts);
|
|
75
23
|
return true;
|
|
76
24
|
} catch (err) {
|
|
77
|
-
|
|
78
|
-
|
|
25
|
+
if (err instanceof DashboardClientError) {
|
|
26
|
+
console.error(pc.red(err.message));
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
console.error(pc.red(`Failed to list secrets: ${toErrorMessage(err)}`));
|
|
79
30
|
return false;
|
|
80
31
|
}
|
|
81
32
|
}
|
|
33
|
+
/** Render the secret-context table to stdout. */
|
|
34
|
+
function renderContextTable(contexts) {
|
|
35
|
+
console.log(pc.bold("\nTest-available secret contexts:\n"));
|
|
36
|
+
const ctxKeys = (c) => c.secretKeys ?? [];
|
|
37
|
+
const nameWidth = Math.max(7, ...contexts.map((c) => c.name.length));
|
|
38
|
+
const keysWidth = Math.max(4, ...contexts.map((c) => {
|
|
39
|
+
const k = ctxKeys(c);
|
|
40
|
+
return k.length > 0 ? k.join(", ").length : 4;
|
|
41
|
+
}));
|
|
42
|
+
const flagsWidth = Math.max(5, ...contexts.map((c) => c.enabled ? 0 : 8));
|
|
43
|
+
const pad = (s, w) => s.padEnd(w);
|
|
44
|
+
const hr = (w) => "─".repeat(w);
|
|
45
|
+
console.log(`┌${hr(nameWidth + 2)}┬${hr(keysWidth + 2)}┬${hr(flagsWidth + 2)}┐`);
|
|
46
|
+
console.log(`│ ${pad("Context", nameWidth)} │ ${pad("Keys", keysWidth)} │ ${pad("Flags", flagsWidth)} │`);
|
|
47
|
+
console.log(`├${hr(nameWidth + 2)}┼${hr(keysWidth + 2)}┼${hr(flagsWidth + 2)}┤`);
|
|
48
|
+
for (const ctx of contexts) {
|
|
49
|
+
const k = ctxKeys(ctx);
|
|
50
|
+
const keys = k.length > 0 ? k.join(", ") : pc.gray("none");
|
|
51
|
+
const keysRaw = k.length > 0 ? k.join(", ") : "none";
|
|
52
|
+
const flagStr = ctx.enabled ? "" : "disabled";
|
|
53
|
+
console.log(`│ ${pad(ctx.name, nameWidth)} │ ${keys}${" ".repeat(Math.max(0, keysWidth - keysRaw.length))} │ ${pad(flagStr, flagsWidth)} │`);
|
|
54
|
+
}
|
|
55
|
+
console.log(`└${hr(nameWidth + 2)}┴${hr(keysWidth + 2)}┴${hr(flagsWidth + 2)}┘`);
|
|
56
|
+
console.log("");
|
|
57
|
+
}
|
|
82
58
|
//#endregion
|
|
83
59
|
export { secretsListCommand };
|
|
84
60
|
|
package/dist/commands/test.d.ts
CHANGED
|
@@ -34,6 +34,10 @@ export interface RemoteRunOptions extends TestOptions {
|
|
|
34
34
|
history?: boolean;
|
|
35
35
|
/** --env KEY=VALUE flag values, uploaded as per-run secrets. */
|
|
36
36
|
envFlags?: string[];
|
|
37
|
+
/** Target organization id (overrides config.activeOrgId). */
|
|
38
|
+
org?: string;
|
|
39
|
+
/** Target orchestrator cluster name (overrides the per-org default). */
|
|
40
|
+
orchestrator?: string;
|
|
37
41
|
}
|
|
38
42
|
/** Result of a single remote fixture run */
|
|
39
43
|
export interface RemoteRunResult {
|
package/dist/commands/test.js
CHANGED
package/dist/commands/types.d.ts
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
export interface TypesOptions {
|
|
2
2
|
/** Path to .kici directory (defaults to .kici) */
|
|
3
3
|
kiciDir?: string;
|
|
4
|
-
/** Orchestrator endpoint override (defaults to global config) */
|
|
5
|
-
endpoint?: string;
|
|
6
4
|
}
|
|
7
5
|
/**
|
|
8
6
|
* Generate TypeScript declarations for environment secrets.
|
|
9
7
|
*
|
|
10
|
-
* Fetches environment metadata
|
|
11
|
-
* .kici/types/secrets.d.ts with module augmentation for
|
|
8
|
+
* Fetches environment metadata (with secret key names) through the Platform
|
|
9
|
+
* and generates .kici/types/secrets.d.ts with module augmentation for
|
|
12
10
|
* KnownSecretKeys and EnvironmentSecrets.
|
|
13
11
|
*
|
|
14
12
|
* @param options - Command options
|
|
15
13
|
* @returns true on success, false on error
|
|
16
14
|
*/
|
|
17
|
-
export declare function typesCommand(options
|
|
15
|
+
export declare function typesCommand(options?: TypesOptions): Promise<boolean>;
|
|
18
16
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/commands/types.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import "../chunk-
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
2
|
import { loadGlobalConfig } from "../remote/config.js";
|
|
3
|
+
import { DashboardClient, DashboardClientError } from "../remote/dashboard-client.js";
|
|
3
4
|
import { generateSecretsDts } from "../generators/secrets-dts.js";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import pc from "picocolors";
|
|
@@ -9,50 +10,22 @@ import { toErrorMessage } from "@kici-dev/core";
|
|
|
9
10
|
/**
|
|
10
11
|
* Generate TypeScript declarations for environment secrets.
|
|
11
12
|
*
|
|
12
|
-
* Fetches environment metadata
|
|
13
|
-
* .kici/types/secrets.d.ts with module augmentation for
|
|
13
|
+
* Fetches environment metadata (with secret key names) through the Platform
|
|
14
|
+
* and generates .kici/types/secrets.d.ts with module augmentation for
|
|
14
15
|
* KnownSecretKeys and EnvironmentSecrets.
|
|
15
16
|
*
|
|
16
17
|
* @param options - Command options
|
|
17
18
|
* @returns true on success, false on error
|
|
18
19
|
*/
|
|
19
|
-
async function typesCommand(options) {
|
|
20
|
+
async function typesCommand(options = {}) {
|
|
20
21
|
try {
|
|
21
22
|
const config = await loadGlobalConfig();
|
|
22
|
-
if (!config.token) {
|
|
23
|
-
console.error(pc.red("Not authenticated. Run `kici login` first to connect to your orchestrator."));
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
const endpoint = options.endpoint ?? config.endpoint;
|
|
27
|
-
if (!endpoint) {
|
|
28
|
-
console.error(pc.red("No orchestrator endpoint configured. Run `kici login --endpoint <url>` first."));
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
if (!config.activeOrgId) {
|
|
32
|
-
console.error(pc.red("No active organization. Run `kici org list` then `kici org use <name>` first."));
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
const url = `${endpoint.replace(/\/+$/, "")}/api/v1/admin/environments?orgId=${encodeURIComponent(config.activeOrgId)}&includeSecrets=true`;
|
|
36
|
-
const res = await fetch(url, { headers: { Authorization: `Bearer ${config.token}` } });
|
|
37
|
-
if (res.status === 401) {
|
|
38
|
-
console.error(pc.red("Authentication failed. Check your API key with `kici login`."));
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
if (res.status === 403) {
|
|
42
|
-
console.error(pc.red("Permission denied. Your API key does not have environments.read access."));
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
if (!res.ok) {
|
|
46
|
-
const text = await res.text();
|
|
47
|
-
console.error(pc.red(`Failed to fetch environments: ${res.status} ${text}`));
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
23
|
const dtsContent = generateSecretsDts({
|
|
51
|
-
environments: (
|
|
24
|
+
environments: (await DashboardClient.fromConfig(config).listEnvironments(true)).map((e) => ({
|
|
52
25
|
name: e.name,
|
|
53
|
-
keys: e.
|
|
26
|
+
keys: e.secretKeys ?? []
|
|
54
27
|
})),
|
|
55
|
-
endpoint: endpoint.replace(/\/+$/, ""),
|
|
28
|
+
endpoint: (config.platformEndpoint ?? config.endpoint ?? "kici Platform").replace(/\/+$/, ""),
|
|
56
29
|
generatedAt: /* @__PURE__ */ new Date()
|
|
57
30
|
});
|
|
58
31
|
const kiciDir = options.kiciDir ?? ".kici";
|
|
@@ -63,8 +36,11 @@ async function typesCommand(options) {
|
|
|
63
36
|
console.log(pc.green("Types generated") + pc.dim(` ${outputPath}`));
|
|
64
37
|
return true;
|
|
65
38
|
} catch (err) {
|
|
66
|
-
|
|
67
|
-
|
|
39
|
+
if (err instanceof DashboardClientError) {
|
|
40
|
+
console.error(pc.red(err.message));
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
console.error(pc.red(`Failed to generate types: ${toErrorMessage(err)}`));
|
|
68
44
|
return false;
|
|
69
45
|
}
|
|
70
46
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface VerifyAttestationOptions {
|
|
2
|
+
/** Path or `http(s)` URL to the attestation bundle JSON. Required. */
|
|
3
|
+
bundle?: string;
|
|
4
|
+
/** Trusted issuer URL (online discovery) or a self-contained `{ issuer, jwks }` file. Required. */
|
|
5
|
+
trustRoot?: string;
|
|
6
|
+
/** Expected token audience (defaults to the KiCI provenance audience). */
|
|
7
|
+
audience?: string;
|
|
8
|
+
/** Emit the structured `VerifyResult` as JSON instead of human output. */
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function verifyAttestationCommand(artifact: string | undefined, options?: VerifyAttestationOptions): Promise<boolean>;
|
|
12
|
+
//# sourceMappingURL=verify-attestation.d.ts.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import "../chunk-BTugEXQM.js";
|
|
2
|
+
import { resolveTrustRoot } from "../provenance-trust-root.js";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { logger, sha256File, toErrorMessage } from "@kici-dev/core";
|
|
6
|
+
import { KICI_PROVENANCE_AUDIENCE } from "@kici-dev/engine/provenance/bundle";
|
|
7
|
+
import { verifyKiciBundle } from "@kici-dev/engine/provenance/verify";
|
|
8
|
+
//#region src/commands/verify-attestation.ts
|
|
9
|
+
/**
|
|
10
|
+
* `kici verify-attestation [artifact] --bundle <path|url> --trust-root <url|file>`
|
|
11
|
+
*
|
|
12
|
+
* Offline verification of a KiCI-signed provenance bundle: read the bundle,
|
|
13
|
+
* resolve the trusted issuer + JWKS out-of-band (`--trust-root`), optionally
|
|
14
|
+
* digest the artifact, and hand everything to the shared browser-safe
|
|
15
|
+
* `verifyKiciBundle` core in `@kici-dev/engine`. The engine owns all crypto;
|
|
16
|
+
* this command is the thin Node wrapper (fs / fetch / artifact digest / output).
|
|
17
|
+
*
|
|
18
|
+
* Returns a boolean (verified) so `cli.ts` can map it to an exit code (0/1).
|
|
19
|
+
*/
|
|
20
|
+
async function verifyAttestationCommand(artifact, options = {}) {
|
|
21
|
+
try {
|
|
22
|
+
if (!options.bundle) {
|
|
23
|
+
logger.error(pc.red("Error: --bundle <path|url> is required"));
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (!options.trustRoot) {
|
|
27
|
+
logger.error(pc.red("Error: --trust-root <url|file> is required"));
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const bundle = JSON.parse(await readBundle(options.bundle));
|
|
31
|
+
const { issuer, jwks } = await resolveTrustRoot(options.trustRoot);
|
|
32
|
+
const expectedDigest = artifact ? {
|
|
33
|
+
alg: "sha256",
|
|
34
|
+
hex: await sha256File(artifact)
|
|
35
|
+
} : void 0;
|
|
36
|
+
const result = await verifyKiciBundle({
|
|
37
|
+
bundle,
|
|
38
|
+
jwks,
|
|
39
|
+
expectedIssuer: issuer,
|
|
40
|
+
expectedAudience: options.audience ?? KICI_PROVENANCE_AUDIENCE,
|
|
41
|
+
expectedDigest
|
|
42
|
+
});
|
|
43
|
+
if (options.json) {
|
|
44
|
+
console.log(JSON.stringify(result, null, 2));
|
|
45
|
+
return result.verified;
|
|
46
|
+
}
|
|
47
|
+
if (result.verified) {
|
|
48
|
+
logger.info(`${pc.green("PASS")} provenance verified (issuer ${issuer})`);
|
|
49
|
+
const c = result.claims ?? {};
|
|
50
|
+
logger.info(pc.gray(` repository=${c.repository} ref=${c.ref} sha=${c.sha} run=${c.kici_run_id} job=${c.kici_job_id}`));
|
|
51
|
+
} else logger.error(`${pc.red("FAIL")} provenance NOT verified: ${result.failures.join(", ")}`);
|
|
52
|
+
return result.verified;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
logger.error(pc.red(`Error: ${toErrorMessage(error)}`));
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function readBundle(bundlePathOrUrl) {
|
|
59
|
+
if (/^https?:\/\//.test(bundlePathOrUrl)) {
|
|
60
|
+
const res = await fetch(bundlePathOrUrl);
|
|
61
|
+
if (!res.ok) throw new Error(`failed to fetch bundle: ${res.status}`);
|
|
62
|
+
return res.text();
|
|
63
|
+
}
|
|
64
|
+
return readFile(bundlePathOrUrl, "utf-8");
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { verifyAttestationCommand };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=verify-attestation.js.map
|
package/dist/commands/watch.js
CHANGED