@kici-dev/compiler 0.1.23 → 0.1.24
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/cli.js +15 -5
- package/dist/commands/index.d.ts +4 -2
- package/dist/commands/index.js +3 -2
- package/dist/commands/init.js +2 -2
- package/dist/commands/pat.d.ts +27 -0
- package/dist/commands/pat.js +76 -0
- package/dist/commands/preview.d.ts +88 -0
- package/dist/commands/{test.js → preview.js} +15 -14
- package/dist/commands/run.d.ts +11 -1
- package/dist/commands/run.js +34 -7
- package/dist/commands/verify-attestation.d.ts +4 -1
- package/dist/commands/verify-attestation.js +26 -10
- package/dist/generators/secrets-dts.js +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/llm-context/llms-architecture.txt +3 -3
- package/dist/llm-context/llms-cli.txt +149 -26
- package/dist/llm-context/llms-features.txt +107 -5
- package/dist/llm-context/llms-full.txt +390 -46
- package/dist/llm-context/llms-getting-started.txt +6 -6
- package/dist/llm-context/llms-sdk.txt +125 -6
- package/dist/llm-context/llms.txt +7 -5
- package/dist/local-executor/index.js +2 -1
- package/dist/local-executor/job-runner.js +3 -3
- package/dist/lockfile/generator.d.ts +10 -2
- package/dist/lockfile/generator.js +106 -52
- package/dist/remote/history.d.ts +1 -1
- package/dist/remote/history.js +1 -1
- package/dist/remote/local-repo-identity.d.ts +32 -0
- package/dist/remote/local-repo-identity.js +74 -0
- package/dist/remote/prod-defaults.d.ts +8 -0
- package/dist/remote/prod-defaults.js +9 -1
- package/dist/templates/agents-md.d.ts +1 -1
- package/dist/templates/agents-md.js +2 -2
- package/dist/templates/package-json.js +1 -1
- package/dist/test-runner/step-context.d.ts +1 -1
- package/dist/test-runner/step-context.js +2 -1
- package/dist/types.d.ts +33 -6
- package/dist/types.js +5 -1
- package/package.json +4 -7
- package/sbom.spdx.json +35 -35
|
@@ -2,6 +2,99 @@
|
|
|
2
2
|
|
|
3
3
|
This bundle covers: Running the CLI: compile, test, run local/remote, auth, hooks, lock-file drift.
|
|
4
4
|
|
|
5
|
+
## Drive KiCI from your coding agent
|
|
6
|
+
|
|
7
|
+
Source: https://docs.kici.dev/user/ai-agents/
|
|
8
|
+
|
|
9
|
+
KiCI ships a hosted **MCP server** so a coding agent (Claude Code, or any MCP
|
|
10
|
+
client) can drive your CI directly: trigger runs, read a structured result,
|
|
11
|
+
fetch the failing step's logs, cancel, and re-run — all under your own identity,
|
|
12
|
+
org-scoped, and audited. There are no per-tool tokens to configure: point the
|
|
13
|
+
agent at one URL with one credential and it's done.
|
|
14
|
+
|
|
15
|
+
The MCP exposes only what you can already do yourself through the `kici` CLI and
|
|
16
|
+
the dashboard. It is not a new privileged surface — every tool maps to an
|
|
17
|
+
existing user-facing operation and is gated by the same permissions your role
|
|
18
|
+
grants.
|
|
19
|
+
|
|
20
|
+
## 1. Mint an agent token
|
|
21
|
+
|
|
22
|
+
The MCP accepts **only** an agent-kind personal access token (PAT). Mint one with
|
|
23
|
+
the `kici` CLI (log in first with `kici login`):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
kici pat create --agent --name "claude-code"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `--name` value is the **agent label**. It is recorded on every action the
|
|
30
|
+
agent takes, so your audit log shows exactly which agent did what (and on whose
|
|
31
|
+
behalf). The token is printed once — save it now; it cannot be retrieved later.
|
|
32
|
+
|
|
33
|
+
An agent PAT inherits your permissions unchanged — it carries provenance, not
|
|
34
|
+
extra authority. Powerful operator capabilities (secret rotation, agent and peer
|
|
35
|
+
management, draining) are intentionally **not** exposed here.
|
|
36
|
+
|
|
37
|
+
## 2. Point your coding agent at the MCP server
|
|
38
|
+
|
|
39
|
+
Configure your MCP client with the KiCI MCP endpoint and the agent PAT as a
|
|
40
|
+
Bearer credential. The endpoint is the hosted Platform URL plus `/api/v1/mcp`.
|
|
41
|
+
|
|
42
|
+
For Claude Code, add a remote MCP server whose URL is your KiCI Platform's
|
|
43
|
+
`/api/v1/mcp` and whose `Authorization` header is `Bearer <your-agent-pat>`.
|
|
44
|
+
|
|
45
|
+
That's the entire setup. The agent can now call the tools below.
|
|
46
|
+
|
|
47
|
+
## 3. What the agent can do
|
|
48
|
+
|
|
49
|
+
**Read**
|
|
50
|
+
|
|
51
|
+
- `list_runs` — recent runs in your organization.
|
|
52
|
+
- `get_run` — the structured, provenance-tagged result of a run: the typed job
|
|
53
|
+
graph, per-step statuses and exit codes, durations, and a derived failure
|
|
54
|
+
category.
|
|
55
|
+
- `get_step_logs` — the log lines for a specific step.
|
|
56
|
+
- `list_workflows` — your registered workflows.
|
|
57
|
+
|
|
58
|
+
**Drive**
|
|
59
|
+
|
|
60
|
+
- `trigger_run` — run a registered workflow ("run now").
|
|
61
|
+
- `rerun_run` — re-run a completed run.
|
|
62
|
+
- `cancel_run` — cancel an in-progress run.
|
|
63
|
+
|
|
64
|
+
If you belong to a single organization, the org is resolved automatically. If
|
|
65
|
+
you belong to several, pass an `orgId` argument to any tool.
|
|
66
|
+
|
|
67
|
+
## 4. Why the structured result is agent-safe
|
|
68
|
+
|
|
69
|
+
`get_run` and `get_step_logs` return a machine-first shape designed for an agent
|
|
70
|
+
to reason over without being misled by repository content. Every field that
|
|
71
|
+
comes from your repo, a contributor, or a process's output — workflow and job
|
|
72
|
+
names, refs, error messages, log lines, job outputs — is wrapped in an
|
|
73
|
+
`{ untrusted: true, value: … }` envelope. KiCI-generated values (ids, statuses,
|
|
74
|
+
exit codes, durations, the derived failure category) are left plain. An agent can
|
|
75
|
+
keep user-controlled content out of its instruction channel by refusing to act
|
|
76
|
+
on anything tagged `untrusted`.
|
|
77
|
+
|
|
78
|
+
Secret values are never returned — only the names of the secret keys a step
|
|
79
|
+
accessed.
|
|
80
|
+
|
|
81
|
+
## 5. The audit guarantee
|
|
82
|
+
|
|
83
|
+
Because the MCP accepts only an agent-kind PAT, **every action that flows through
|
|
84
|
+
it is agent-attributed by construction** — there is no path that produces an
|
|
85
|
+
untagged, human-looking action. Each read and each drive operation is recorded in
|
|
86
|
+
your orchestrator's access log under your identity plus the agent label, so you
|
|
87
|
+
always have a complete trail of what your agent did.
|
|
88
|
+
|
|
89
|
+
Inspect that trail with `kici-admin access-log list --json` (or
|
|
90
|
+
`kici-admin access-log show <id>` for one entry). An agent-attributed row keeps
|
|
91
|
+
`actor_type` as `user` and `actor_id` as your own identity — the agent provenance
|
|
92
|
+
rides in the row's actor metadata as `agentLabel` (the `--name` you minted the
|
|
93
|
+
PAT with) and `agentPatId` (the token that acted). The label is also stored in a
|
|
94
|
+
dedicated `agent_label` column on every such row.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
5
98
|
## CLI authentication
|
|
6
99
|
|
|
7
100
|
Source: https://docs.kici.dev/user/cli-auth/
|
|
@@ -284,7 +377,7 @@ Run commands with `npx kici` or add scripts to your `package.json`:
|
|
|
284
377
|
{
|
|
285
378
|
"scripts": {
|
|
286
379
|
"kici:compile": "kici compile",
|
|
287
|
-
"kici:
|
|
380
|
+
"kici:preview": "kici preview"
|
|
288
381
|
}
|
|
289
382
|
}
|
|
290
383
|
```
|
|
@@ -379,6 +472,8 @@ kici run local [event] [options]
|
|
|
379
472
|
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
380
473
|
| `--in-place` | `false` | Run against the real working directory instead of an isolated tmp checkout (see "Execution isolation" below) |
|
|
381
474
|
| `--keep` | `false` | Always retain the isolated tmp checkout (default: keep only on failure) |
|
|
475
|
+
| `--check` | `false` | Run in [check mode](https://docs.kici.dev/user/idempotent-steps/): each step reports drift instead of applying; the run still exits 0 |
|
|
476
|
+
| `--fail-on-drift` | `false` | In check mode, exit non-zero if any step reports drift (no effect without `--check`) |
|
|
382
477
|
|
|
383
478
|
**Interactive workflow selection (`--pick` / `-p`):**
|
|
384
479
|
|
|
@@ -520,6 +615,10 @@ kici run remote [fixture] [options]
|
|
|
520
615
|
| `--target-allow-empty` | `false` | A `--target` that narrows a `runsOnAll` job to zero hosts skips it instead of failing |
|
|
521
616
|
| `--debug` | `false` | Verbose internals |
|
|
522
617
|
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
618
|
+
| `--routing-key <key>` | none | Override the routing key for this run (advanced; selecting the org normally suffices — see [How the run is routed](https://docs.kici.dev/user/cli-reference/#how-the-run-is-routed)) |
|
|
619
|
+
| `--check` | `false` | Run in [check mode](https://docs.kici.dev/user/idempotent-steps/): each step reports drift instead of applying |
|
|
620
|
+
| `--fail-on-drift` | `false` | In check mode, fail the run if any step reports drift (no effect without `--check`) |
|
|
621
|
+
| `--approve-all, --yes` | `false` | Auto-approve every [approval gate](https://docs.kici.dev/user/approvals/) this run holds on (run-scoped; eligibility still enforced) |
|
|
523
622
|
|
|
524
623
|
**Examples:**
|
|
525
624
|
|
|
@@ -685,12 +784,12 @@ kici orchestrators use us-east
|
|
|
685
784
|
kici orchestrators use us-east --org xyz789ghi012
|
|
686
785
|
```
|
|
687
786
|
|
|
688
|
-
### kici
|
|
787
|
+
### kici preview
|
|
689
788
|
|
|
690
789
|
Preview which workflows match a trigger event (dry-run, no execution). Useful for verifying trigger configurations during development.
|
|
691
790
|
|
|
692
791
|
```bash
|
|
693
|
-
kici
|
|
792
|
+
kici preview [event] [options]
|
|
694
793
|
```
|
|
695
794
|
|
|
696
795
|
**Arguments:**
|
|
@@ -717,19 +816,19 @@ kici test [event] [options]
|
|
|
717
816
|
|
|
718
817
|
```bash
|
|
719
818
|
# Preview which workflows match a push event
|
|
720
|
-
kici
|
|
819
|
+
kici preview push
|
|
721
820
|
|
|
722
821
|
# Preview PR trigger matching
|
|
723
|
-
kici
|
|
822
|
+
kici preview pr:open
|
|
724
823
|
|
|
725
824
|
# Preview with branch override
|
|
726
|
-
kici
|
|
825
|
+
kici preview push --branch develop
|
|
727
826
|
|
|
728
827
|
# Filter to specific workflow
|
|
729
|
-
kici
|
|
828
|
+
kici preview push --workflow ci
|
|
730
829
|
|
|
731
830
|
# Simulate changed files for path-filtered triggers
|
|
732
|
-
kici
|
|
831
|
+
kici preview push --files src/index.ts --files README.md
|
|
733
832
|
```
|
|
734
833
|
|
|
735
834
|
**Exit codes:**
|
|
@@ -739,7 +838,7 @@ kici test push --files src/index.ts --files README.md
|
|
|
739
838
|
| 0 | Preview completed (including zero matches) |
|
|
740
839
|
| 1 | Error |
|
|
741
840
|
|
|
742
|
-
**Migration from old `
|
|
841
|
+
**Migration from the old `test` command:** The dry-run preview command was renamed from `test` to `preview`. If you were using the old `test` command with a fixture name for remote fixture execution, use `kici run remote <fixture-name>` instead. For local workflow execution, use `kici run local <event>`.
|
|
743
842
|
|
|
744
843
|
### kici login
|
|
745
844
|
|
|
@@ -1116,6 +1215,27 @@ Only key names are shown — secret values are never returned over this endpoint
|
|
|
1116
1215
|
|
|
1117
1216
|
**Prerequisites:** authenticate via `kici login` and select an active organization with `kici org use <name>`.
|
|
1118
1217
|
|
|
1218
|
+
### kici pat create
|
|
1219
|
+
|
|
1220
|
+
Mint a personal access token under your own identity. Pass `--agent` to mint an
|
|
1221
|
+
**agent-kind** PAT — the credential a coding agent points the KiCI MCP server at.
|
|
1222
|
+
|
|
1223
|
+
```bash
|
|
1224
|
+
kici pat create --agent --name "claude-code"
|
|
1225
|
+
```
|
|
1226
|
+
|
|
1227
|
+
- `--agent` marks the token as agent-kind. An agent PAT inherits your
|
|
1228
|
+
permissions unchanged (it carries provenance, not extra authority) and is the
|
|
1229
|
+
**only** credential the MCP server accepts.
|
|
1230
|
+
- `--name <label>` sets the token name. For an agent PAT this is the **agent
|
|
1231
|
+
label** recorded on every action the agent takes — required with `--agent`.
|
|
1232
|
+
- `--expires-in-days <n>` overrides the default expiry.
|
|
1233
|
+
|
|
1234
|
+
The token is printed once — save it immediately; it cannot be retrieved later.
|
|
1235
|
+
See [Drive KiCI from your coding agent](https://docs.kici.dev/user/ai-agents/) for the full setup.
|
|
1236
|
+
|
|
1237
|
+
**Prerequisites:** authenticate via `kici login` first.
|
|
1238
|
+
|
|
1119
1239
|
### kici types
|
|
1120
1240
|
|
|
1121
1241
|
Generate TypeScript declaration files from orchestrator environment metadata. The generated `.d.ts` file augments the SDK's `KnownSecretKeys` and `EnvironmentSecrets` interfaces, providing compile-time autocomplete and type checking for secret key names.
|
|
@@ -1434,7 +1554,7 @@ kici admin drain-worker --url http://worker-2.internal:10143
|
|
|
1434
1554
|
Verify a KiCI build-provenance attestation bundle offline. A bundle is the signed package a workflow step produces via `ctx.attestProvenance(...)`: a DSSE-wrapped SLSA in-toto statement, the ephemeral public key that signed it, and the KiCI identity token that anchors the build context. For the end-to-end attest → verify → view journey, see the [build provenance guide](https://docs.kici.dev/user/provenance/). Verification establishes the full chain — the identity token verifies against the trusted issuer's JWKS, the DSSE signature verifies against the bundled key, and the statement's build context must match the token's claims (a mismatch is a hard failure). When an `[artifact]` is given, its SHA-256 digest is also matched against the attestation subject.
|
|
1435
1555
|
|
|
1436
1556
|
```bash
|
|
1437
|
-
kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-file> [options]
|
|
1557
|
+
kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-file>] [options]
|
|
1438
1558
|
```
|
|
1439
1559
|
|
|
1440
1560
|
**Arguments:**
|
|
@@ -1445,14 +1565,14 @@ kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-f
|
|
|
1445
1565
|
|
|
1446
1566
|
**Options:**
|
|
1447
1567
|
|
|
1448
|
-
| Option | Required | Description
|
|
1449
|
-
| ---------------------------- | -------- |
|
|
1450
|
-
| `--bundle <path-or-url>` | yes | Path or `http(s)` URL to the attestation bundle JSON.
|
|
1451
|
-
| `--trust-root <url-or-file>` |
|
|
1452
|
-
| `--audience <aud>` | no | Expected token audience (defaults to the KiCI provenance audience).
|
|
1453
|
-
| `--json` | no | Print the structured verification result as JSON instead of human-readable output.
|
|
1568
|
+
| Option | Required | Description |
|
|
1569
|
+
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
1570
|
+
| `--bundle <path-or-url>` | yes | Path or `http(s)` URL to the attestation bundle JSON. |
|
|
1571
|
+
| `--trust-root <url-or-file>` | no | Trusted issuer (see below). Defaults to the hosted KiCI platform. The token issuer is pinned to it, never taken from the token. |
|
|
1572
|
+
| `--audience <aud>` | no | Expected token audience (defaults to the KiCI provenance audience). |
|
|
1573
|
+
| `--json` | no | Print the structured verification result as JSON instead of human-readable output. |
|
|
1454
1574
|
|
|
1455
|
-
**Trust root:** the verifier never trusts the issuer named inside the token
|
|
1575
|
+
**Trust root:** `--trust-root` defaults to the hosted KiCI platform's provenance issuer — the same platform you `kici login` against (see [Which trust root do I use?](https://docs.kici.dev/user/provenance/#which-trust-root-do-i-use)), so the common case needs no flag. The verifier never trusts the issuer named inside the token; supplying it out-of-band is what prevents a forged bundle from self-attesting. To override the default, pass `--trust-root` in one of two forms:
|
|
1456
1576
|
|
|
1457
1577
|
- **Online — an HTTPS issuer URL.** The verifier fetches `<url>/.well-known/openid-configuration`, reads its `issuer` and `jwks_uri`, and fetches the JWKS. The token's `iss` is pinned to the discovery document's `issuer`.
|
|
1458
1578
|
- **Offline — a self-contained trust-root file.** A local JSON file with the issuer and JWKS inlined, so no network access is needed (air-gapped verification):
|
|
@@ -1471,7 +1591,10 @@ kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-f
|
|
|
1471
1591
|
**Examples:**
|
|
1472
1592
|
|
|
1473
1593
|
```bash
|
|
1474
|
-
#
|
|
1594
|
+
# Default: verify against the hosted KiCI platform (no --trust-root needed)
|
|
1595
|
+
kici verify-attestation ./dist/app.tgz --bundle ./app.tgz.kici.json
|
|
1596
|
+
|
|
1597
|
+
# Override: verify a bundle against a specific issuer, digest-checking the artifact
|
|
1475
1598
|
kici verify-attestation ./dist/app.tgz \
|
|
1476
1599
|
--bundle ./app.tgz.kici.json \
|
|
1477
1600
|
--trust-root https://platform.example/issuer
|
|
@@ -1488,10 +1611,10 @@ kici verify-attestation --bundle ./app.tgz.kici.json \
|
|
|
1488
1611
|
|
|
1489
1612
|
**Exit codes:**
|
|
1490
1613
|
|
|
1491
|
-
| Code | Meaning
|
|
1492
|
-
| ---- |
|
|
1493
|
-
| 0 | Verified — signature, identity, build context (and digest, if checked) all pass
|
|
1494
|
-
| 1 | Not verified, or an error (missing
|
|
1614
|
+
| Code | Meaning |
|
|
1615
|
+
| ---- | ----------------------------------------------------------------------------------------- |
|
|
1616
|
+
| 0 | Verified — signature, identity, build context (and digest, if checked) all pass |
|
|
1617
|
+
| 1 | Not verified, or an error (missing `--bundle`, unreadable bundle, unreachable trust root) |
|
|
1495
1618
|
|
|
1496
1619
|
## Workflow discovery
|
|
1497
1620
|
|
|
@@ -1533,7 +1656,7 @@ All commands follow a consistent exit code convention:
|
|
|
1533
1656
|
|
|
1534
1657
|
## Debug output
|
|
1535
1658
|
|
|
1536
|
-
Use `--debug` (on `kici run local`, `kici run remote`, `kici
|
|
1659
|
+
Use `--debug` (on `kici run local`, `kici run remote`, `kici preview`) or `--verbose` (on `kici compile`) for detailed output:
|
|
1537
1660
|
|
|
1538
1661
|
```bash
|
|
1539
1662
|
# Shows trigger matching, rule evaluation, decision traces
|
|
@@ -1543,7 +1666,7 @@ kici run local push --debug
|
|
|
1543
1666
|
kici compile --verbose
|
|
1544
1667
|
|
|
1545
1668
|
# Shows trigger matching preview
|
|
1546
|
-
kici
|
|
1669
|
+
kici preview pr:open --debug
|
|
1547
1670
|
```
|
|
1548
1671
|
|
|
1549
1672
|
Set `KICI_DEBUG=true` for additional internal debug output across all commands.
|
|
@@ -1824,7 +1947,7 @@ The lock file (`kici.lock.json`) is a JSON file with the following top-level fie
|
|
|
1824
1947
|
|
|
1825
1948
|
| Field | Description |
|
|
1826
1949
|
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1827
|
-
| `schemaVersion` | Lock file schema version (currently
|
|
1950
|
+
| `schemaVersion` | Lock file schema version (currently 29). Incremented on breaking format changes. |
|
|
1828
1951
|
| `source` | Reference to the source file and export (e.g., `{ file: “.kici/workflows/ci.ts”, export: “#default” }`). |
|
|
1829
1952
|
| `contentHash` | SHA-256 of the serialized lock file content (excluding itself). Changes when any workflow, trigger, or job changes. |
|
|
1830
1953
|
| `lockfileHash` | SHA-256 of the detected package manager's lockfile, used as the dependency cache key. The lockfile is `.kici/package-lock.json` for npm, or the repo-root `pnpm-lock.yaml` / `yarn.lock` for a pnpm/yarn workspace; the hash input is prefixed with the manager name so a manager change is a guaranteed cache miss. Omitted when no lockfile exists. |
|
|
@@ -1947,7 +2070,7 @@ Test your workflows remotely against the full CI pipeline from your local machin
|
|
|
1947
2070
|
- Give test runs test-scoped secrets — your local secret files and `--env` values (uploaded encrypted) plus any environment flagged `allowLocalExecution: true` — while production environments stay unreachable
|
|
1948
2071
|
- Detect test mode in workflow code via `ctx.isTestRun`
|
|
1949
2072
|
|
|
1950
|
-
The command is remote-only -- all execution happens on the orchestrator and agent. For local-only trigger matching previews, use `kici
|
|
2073
|
+
The command is remote-only -- all execution happens on the orchestrator and agent. For local-only trigger matching previews, use `kici preview <event>`.
|
|
1951
2074
|
|
|
1952
2075
|
:::note[Orchestrator prerequisite: cache storage]
|
|
1953
2076
|
`kici run remote` uploads your working-tree overlay to the orchestrator's **cache storage** via a pre-signed URL, and the agent fetches it from there (see [Repo state transfer](https://docs.kici.dev/user/testing-guide/#repo-state-transfer)). The target orchestrator must therefore have cache storage enabled (`KICI_STORAGE_TYPE` = `s3` or `filesystem`).
|
|
@@ -802,6 +802,36 @@ job('deploy-review', {
|
|
|
802
802
|
|
|
803
803
|
A pure function like the one above (see [Dynamic values](https://docs.kici.dev/user/dynamic-values/)) is evaluated inline at dispatch with no init-job overhead. Dynamic environments that match a glob pattern (e.g., `review/*`) inherit the pattern's configuration, variables, and protection rules.
|
|
804
804
|
|
|
805
|
+
### Multiple environments per job
|
|
806
|
+
|
|
807
|
+
A job can bind more than one environment with `environments`, an ordered array. This lets a single job draw secrets and variables from several environments at once — for example a shared `staging` environment plus a `my-testing` environment that carries test-only variables:
|
|
808
|
+
|
|
809
|
+
```typescript
|
|
810
|
+
job('deploy', {
|
|
811
|
+
runsOn: 'default',
|
|
812
|
+
environments: ['staging', 'my-testing'],
|
|
813
|
+
steps: [
|
|
814
|
+
step('deploy', async (ctx) => {
|
|
815
|
+
// ctx.secrets and ctx.env carry the merged set from both environments
|
|
816
|
+
const dbUrl = await ctx.secrets.get('DB_URL');
|
|
817
|
+
}),
|
|
818
|
+
],
|
|
819
|
+
});
|
|
820
|
+
```
|
|
821
|
+
|
|
822
|
+
- `environment` (singular) and `environments` (array) are mutually exclusive — setting both is a compile error. `environment: 'staging'` is exactly equivalent to `environments: ['staging']`.
|
|
823
|
+
- Each array entry is a static name or a function of the event, resolved per element exactly like a single dynamic environment.
|
|
824
|
+
|
|
825
|
+
**Merge order — last wins.** All bound environments are resolved on every dispatch (webhook, scheduled, and test runs alike) and merged in array order. When the same secret or variable key is defined in more than one environment, the later entry in the array wins. With `environments: ['staging', 'my-testing']`, a key defined in both resolves to `my-testing`'s value; keys defined in only one are preserved. The longest-scope-path-wins rule still applies _within_ each environment.
|
|
826
|
+
|
|
827
|
+
**Protection rules combine all-must-pass.** A job must satisfy **every** bound environment's gates — adding an environment can never loosen access. Branch restrictions, trigger-type filters, and repo patterns must pass for all environments; the minimum trust tier is the most restrictive across them; required reviewers are the union of all environments' reviewers; the wait timer is the longest; and the hold expiry is the shortest. If a run is gated out, the rejection names which environment and which rule rejected it (visible via `kici status` and the run's rejection reason), so a mutually-exclusive set of rules surfaces as a clear failure rather than a silent perpetual rejection.
|
|
828
|
+
|
|
829
|
+
**Skip-on-test.** On a test or local run (`kici run remote`, `kici run local`), any bound environment that disallows local execution is skipped — its variables and secrets are omitted from the merge and its gates are not evaluated. This makes the test-only-variables pattern work: with `environments: ['staging', 'my-testing']` where only `my-testing` allows local execution, a test run resolves just `my-testing`'s variables. If every bound environment disallows test runs, the job runs with no environment variables and a clear warning.
|
|
830
|
+
|
|
831
|
+
**Unconfigured environments contribute nothing at dispatch.** At dispatch time a bound environment name with no matching configured environment (and no matching glob environment) simply adds no variables, secrets, or protection rules — the job still runs, exactly as a single dynamic environment resolving to an as-yet-unconfigured name does today.
|
|
832
|
+
|
|
833
|
+
**Registration rejects a provably-unsatisfiable binding.** When a workflow is registered, KiCI statically checks every multi-environment binding: a bound environment that does not exist, a disabled one, or two environments with mutually-exclusive fixed branch / trigger-type / repository restrictions (no value can satisfy both) makes the binding provably unsatisfiable, and the registration is rejected with a precise message naming the job, the environments, and the rule — for example `unsatisfiable environment binding: job 'deploy' binds environments [staging, my-testing] with mutually exclusive branch restrictions (no value satisfies all bound environments)`. Bindings whose restrictions use globs are undecidable at registration and fall through to the dispatch-time gate check instead.
|
|
834
|
+
|
|
805
835
|
### Job-level environment variables
|
|
806
836
|
|
|
807
837
|
The `env` property on a job provides static or dynamic environment variables:
|
|
@@ -841,7 +871,7 @@ job('deploy', {
|
|
|
841
871
|
});
|
|
842
872
|
```
|
|
843
873
|
|
|
844
|
-
If no `concurrencyGroup` is specified, the environment name is used as the default concurrency group.
|
|
874
|
+
If no `concurrencyGroup` is specified, the environment name is used as the default concurrency group. For a job bound to multiple environments, the default is the **first** bound environment's name.
|
|
845
875
|
|
|
846
876
|
### Step context
|
|
847
877
|
|
|
@@ -982,6 +1012,12 @@ Each environment has four tabs:
|
|
|
982
1012
|
|
|
983
1013
|
4. **History** -- view filtered runs targeting this environment.
|
|
984
1014
|
|
|
1015
|
+
### Bound environments on runs
|
|
1016
|
+
|
|
1017
|
+
A job's bound deployment environments are shown as chips on the run detail page (in the job metadata panel) in the order the job declared them, and the distinct set across a run's jobs appears as compact chips on the run list. For a multi-environment job the chips read left-to-right in merge order — later environments override earlier ones on key collisions. A `(dynamic)` chip marks an environment whose name is computed at runtime; it resolves to the real name once the run starts. A job that binds a single environment shows one chip; a job that binds none shows no chip.
|
|
1018
|
+
|
|
1019
|
+
If a multi-environment binding is gated out, the run's failure banner names which environment and which rule rejected it (the same all-must-pass detail surfaced by `kici status`).
|
|
1020
|
+
|
|
985
1021
|
### Secrets management
|
|
986
1022
|
|
|
987
1023
|
Secrets are individual encrypted values organized by scope paths (e.g., `aws/prod`, `databases/postgres`). Scopes are bound to environments via bindings:
|
|
@@ -2005,11 +2041,34 @@ statement's build context must match the token's identity claims (a mismatch is
|
|
|
2005
2041
|
a hard failure).
|
|
2006
2042
|
|
|
2007
2043
|
```bash
|
|
2008
|
-
kici verify-attestation [artifact] --bundle <path-or-url> --trust-root <url-or-file>
|
|
2044
|
+
kici verify-attestation [artifact] --bundle <path-or-url> [--trust-root <url-or-file>]
|
|
2009
2045
|
```
|
|
2010
2046
|
|
|
2011
|
-
|
|
2012
|
-
|
|
2047
|
+
### Which trust root do I use?
|
|
2048
|
+
|
|
2049
|
+
The trust root is the **KiCI platform's provenance issuer** — the same hosted
|
|
2050
|
+
KiCI platform you `kici login` against. KiCI attestations are issued by, and
|
|
2051
|
+
verified against, that one issuer; there are no competing "roots" to choose
|
|
2052
|
+
between. So the answer to "shouldn't I just use KiCI as the trust root?" is yes
|
|
2053
|
+
— and that's the **default**: omit `--trust-root` and the verifier checks the
|
|
2054
|
+
bundle against the hosted KiCI platform automatically. You only pass
|
|
2055
|
+
`--trust-root` to verify against a different environment or, more commonly, an
|
|
2056
|
+
offline `{ issuer, jwks }` file for air-gapped checks.
|
|
2057
|
+
|
|
2058
|
+
### Why you supply it out-of-band
|
|
2059
|
+
|
|
2060
|
+
Given there's a single issuer, why pass it at all instead of letting the
|
|
2061
|
+
verifier read it from the token? Because the issuer named **inside** a token
|
|
2062
|
+
cannot be trusted: a forged bundle could carry a token that names
|
|
2063
|
+
`iss: https://attacker.example` _and_ bundle a key set that "verifies" it,
|
|
2064
|
+
making the whole signature chain circular and self-attesting. The verifier
|
|
2065
|
+
therefore pins to an issuer you supply out-of-band and checks the token against
|
|
2066
|
+
_that_ — the bundle is verified against a key set you trust, not one it shipped
|
|
2067
|
+
with. Naming the trust root is a security requirement, not a multiple-choice
|
|
2068
|
+
question.
|
|
2069
|
+
|
|
2070
|
+
To override the default, supply the trusted issuer via `--trust-root`, in one of
|
|
2071
|
+
two forms:
|
|
2013
2072
|
|
|
2014
2073
|
- **Online — an HTTPS issuer URL.** The verifier fetches
|
|
2015
2074
|
`<url>/.well-known/openid-configuration`, reads its `issuer` and `jwks_uri`,
|
|
@@ -2037,7 +2096,10 @@ when it does not (or on an error such as a missing flag or unreachable trust
|
|
|
2037
2096
|
root).
|
|
2038
2097
|
|
|
2039
2098
|
```bash
|
|
2040
|
-
#
|
|
2099
|
+
# Default: verify against the hosted KiCI platform (no --trust-root needed):
|
|
2100
|
+
kici verify-attestation ./dist/app.tgz --bundle ./app.tgz.kici.json
|
|
2101
|
+
|
|
2102
|
+
# Override the trust root to verify against a specific issuer:
|
|
2041
2103
|
kici verify-attestation ./dist/app.tgz \
|
|
2042
2104
|
--bundle ./app.tgz.kici.json \
|
|
2043
2105
|
--trust-root https://platform.example/issuer
|
|
@@ -2076,6 +2138,44 @@ attestations shows an empty state.
|
|
|
2076
2138
|
|
|
2077
2139
|
<!-- /help:run-attestations -->
|
|
2078
2140
|
|
|
2141
|
+
## Browsing attestations across runs
|
|
2142
|
+
|
|
2143
|
+
The **Attestations** page (in the org sidebar) lists every build-provenance
|
|
2144
|
+
attestation your organization has produced — not just one run's. It is the
|
|
2145
|
+
supply-chain audit surface: look up "who built `sha256:…`?" by digest, or browse
|
|
2146
|
+
and filter every attestation across all runs.
|
|
2147
|
+
|
|
2148
|
+
<!-- help:attestations-list#browsing-attestations-across-runs -->
|
|
2149
|
+
|
|
2150
|
+
The **Attestations** page lists every build-provenance attestation your organization has produced.
|
|
2151
|
+
|
|
2152
|
+
- **Search** by artifact digest (exact `sha256:…`) or name to trace a specific artifact.
|
|
2153
|
+
- **Filter** by verification status, repository, workflow, job, or date.
|
|
2154
|
+
- Each row's **status badge** is the verdict KiCI recorded when the attestation was produced (`verified`, `failed`, `unverifiable`, or `pending`).
|
|
2155
|
+
|
|
2156
|
+
Open a row for the parsed provenance statement and a live re-verification.
|
|
2157
|
+
|
|
2158
|
+
<!-- /help:attestations-list -->
|
|
2159
|
+
|
|
2160
|
+
The status badge here is the **server-side verdict**, computed once when the
|
|
2161
|
+
attestation was recorded (verify-at-ingest) — so the list stays fast at any
|
|
2162
|
+
size. `verified` means the signature, build identity, and build context all
|
|
2163
|
+
checked out against the provenance issuer; `failed` means verification ran and
|
|
2164
|
+
the bundle did not pass; `unverifiable` means no verdict could be computed (no
|
|
2165
|
+
provenance issuer configured, or its keys could not be read — not a forgery
|
|
2166
|
+
signal); `pending` means the verdict has not been computed yet.
|
|
2167
|
+
|
|
2168
|
+
Opening a row leads to the **attestation detail page**:
|
|
2169
|
+
|
|
2170
|
+
<!-- help:attestation-detail#browsing-attestations-across-runs -->
|
|
2171
|
+
|
|
2172
|
+
This page shows the parsed provenance for one attestation.
|
|
2173
|
+
|
|
2174
|
+
- **Builder identity, source, and build type** come from the signed SLSA statement.
|
|
2175
|
+
- The **stored badge** is the verdict recorded at build time; **Re-verify** runs the check live in your browser against the current signing keys.
|
|
2176
|
+
- **Download** exports the signed bundle for offline verification with `kici verify-attestation`.
|
|
2177
|
+
<!-- /help:attestation-detail -->
|
|
2178
|
+
|
|
2079
2179
|
## See also
|
|
2080
2180
|
|
|
2081
2181
|
- [SDK runtime reference](https://docs.kici.dev/user/sdk/runtime/) — the `ctx.attestProvenance` and
|
|
@@ -2097,6 +2197,8 @@ Secrets are managed per-environment in the orchestrator (see [operator docs](htt
|
|
|
2097
2197
|
|
|
2098
2198
|
This design prevents accidental secret leakage through child processes, log output, or error messages. Only secrets you explicitly request are loaded into memory.
|
|
2099
2199
|
|
|
2200
|
+
A job can bind several environments with `environments: ['staging', 'my-testing']`; the secret keys from all bound environments are merged in array order, with a later environment's value winning on a key collision. See [Multiple environments per job](https://docs.kici.dev/user/environments/#multiple-environments-per-job).
|
|
2201
|
+
|
|
2100
2202
|
## Where secret values come from
|
|
2101
2203
|
|
|
2102
2204
|
Secret values are written either through the dashboard or through `kici-admin` running against the orchestrator. The orchestrator operator decides — per organization — which surface accepts secret writes. From the workflow author's perspective, the resolution path at run time is identical either way; the difference is where you (or your ops team) **enter** the value.
|