@kici-dev/compiler 0.1.3 → 0.1.6
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 +5 -3
- package/dist/commands/login.js +4 -6
- package/dist/commands/status.js +1 -1
- package/dist/execution/executor.js +1 -1
- package/dist/llm-context/llms-full.txt +269 -41
- package/dist/llm-context/llms.txt +1 -0
- package/dist/local-executor/index.js +30 -13
- package/dist/local-executor/job-runner.d.ts +4 -2
- package/dist/local-executor/job-runner.js +1 -1
- package/dist/local-executor/materializer.d.ts +39 -0
- package/dist/local-executor/materializer.js +111 -0
- package/dist/local-executor/types.d.ts +4 -0
- package/dist/remote/oauth.d.ts +9 -8
- package/dist/remote/oauth.js +32 -23
- package/dist/remote/oidc-discovery.d.ts +39 -0
- package/dist/remote/oidc-discovery.js +72 -0
- package/dist/remote/uploader.d.ts +35 -0
- package/dist/remote/uploader.js +32 -7
- package/dist/templates/package-json.js +1 -1
- package/package.json +4 -5
- package/sbom.spdx.json +52 -47
package/dist/cli.js
CHANGED
|
@@ -22,7 +22,7 @@ import "./commands/index.js";
|
|
|
22
22
|
import { Argument, Command, Option } from "commander";
|
|
23
23
|
import pc from "picocolors";
|
|
24
24
|
//#region src/cli.ts
|
|
25
|
-
const version = "0.1.
|
|
25
|
+
const version = "0.1.6";
|
|
26
26
|
const program = new Command();
|
|
27
27
|
program.name("kici").description("KiCI workflow compiler").version(version);
|
|
28
28
|
program.hook("preAction", () => {
|
|
@@ -50,7 +50,7 @@ program.command("fixture").addArgument(fixtureEventArg).description("Generate fi
|
|
|
50
50
|
await fixtureCommand(event, options);
|
|
51
51
|
});
|
|
52
52
|
const runCommand = program.command("run").description("Execute workflows locally or remotely");
|
|
53
|
-
runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open, schedule) — optional with --pick").description("Execute workflows locally without orchestrator infrastructure").option("-p, --pick", "Interactively pick a workflow and trigger to simulate", false).option("--workflow <name>", "Run only the specified workflow").option("--job <name>", "Run only the specified job (and its dependencies)").option("--branch <name>", "Override detected git branch").option("--sha <hash>", "Override detected git SHA").option("--payload <path>", "Path to explicit event payload JSON file").option("--concurrency <n>", "Max parallel jobs (default: CPU cores)", parseInt).option("--keep-going", "Continue after job failure", false).option("--container", "Use Podman container isolation", false).option("--env <KEY=VALUE>", "Environment variable override (repeatable)", (val, prev) => [...prev, val], []).option("--quiet", "Suppress streaming output", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--files <path>", "Override changed file paths (repeatable, default: git diff)", (val, prev) => [...prev, val], []).option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").action(async (event, options) => {
|
|
53
|
+
runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open, schedule) — optional with --pick").description("Execute workflows locally without orchestrator infrastructure").option("-p, --pick", "Interactively pick a workflow and trigger to simulate", false).option("--workflow <name>", "Run only the specified workflow").option("--job <name>", "Run only the specified job (and its dependencies)").option("--branch <name>", "Override detected git branch").option("--sha <hash>", "Override detected git SHA").option("--payload <path>", "Path to explicit event payload JSON file").option("--concurrency <n>", "Max parallel jobs (default: CPU cores)", parseInt).option("--keep-going", "Continue after job failure", false).option("--container", "Use Podman container isolation", false).option("--env <KEY=VALUE>", "Environment variable override (repeatable)", (val, prev) => [...prev, val], []).option("--quiet", "Suppress streaming output", false).option("--json", "Output structured JSON result", false).option("--junit <path>", "Output JUnit XML result").option("--files <path>", "Override changed file paths (repeatable, default: git diff)", (val, prev) => [...prev, val], []).option("--debug", "Verbose internals", false).option("--kici-dir <path>", "Path to .kici directory", ".kici").option("--in-place", "Run against the real working directory instead of an isolated tmp checkout", false).option("--keep", "Always retain the isolated tmp checkout (default: keep only on failure)", false).action(async (event, options) => {
|
|
54
54
|
if (options.pick && options.workflow) {
|
|
55
55
|
console.error("Error: --pick is mutually exclusive with --workflow.");
|
|
56
56
|
process.exit(2);
|
|
@@ -76,7 +76,9 @@ runCommand.command("local").argument("[event]", "Event type (e.g., push, pr:open
|
|
|
76
76
|
junit: options.junit,
|
|
77
77
|
files: options.files,
|
|
78
78
|
debug: options.debug,
|
|
79
|
-
kiciDir: options.kiciDir
|
|
79
|
+
kiciDir: options.kiciDir,
|
|
80
|
+
inPlace: options.inPlace,
|
|
81
|
+
keep: options.keep
|
|
80
82
|
});
|
|
81
83
|
process.exit(success ? 0 : 1);
|
|
82
84
|
});
|
package/dist/commands/login.js
CHANGED
|
@@ -48,16 +48,15 @@ async function oauthLogin(options) {
|
|
|
48
48
|
const platformUrl = options.platformEndpoint || process.env.KICI_PLATFORM_URL || "";
|
|
49
49
|
const issuer = process.env.KICI_OIDC_ISSUER || "";
|
|
50
50
|
const clientId = process.env.KICI_OIDC_CLIENT_ID || "";
|
|
51
|
-
const projectId = process.env.KICI_OIDC_PROJECT_ID || "";
|
|
52
51
|
const missing = [];
|
|
53
52
|
if (!platformUrl) missing.push("KICI_PLATFORM_URL");
|
|
54
53
|
if (!issuer) missing.push("KICI_OIDC_ISSUER");
|
|
55
54
|
if (!clientId) missing.push("KICI_OIDC_CLIENT_ID");
|
|
56
55
|
if (missing.length > 0) {
|
|
57
56
|
console.error(pc.red(`Error: missing required env var(s) for OAuth login: ${missing.join(", ")}`));
|
|
58
|
-
console.error(pc.gray(" Set them to your Platform and
|
|
57
|
+
console.error(pc.gray(" Set them to your Platform and IdP endpoints, for example:"));
|
|
59
58
|
console.error(pc.gray(" export KICI_PLATFORM_URL=https://your-platform.example.com"));
|
|
60
|
-
console.error(pc.gray(" export KICI_OIDC_ISSUER=https://your-
|
|
59
|
+
console.error(pc.gray(" export KICI_OIDC_ISSUER=https://your-idp.example.com"));
|
|
61
60
|
console.error(pc.gray(" export KICI_OIDC_CLIENT_ID=<cli-client-id>"));
|
|
62
61
|
return false;
|
|
63
62
|
}
|
|
@@ -66,12 +65,11 @@ async function oauthLogin(options) {
|
|
|
66
65
|
const useDeviceFlow = options.device || !browserCmdSet && isHeadless();
|
|
67
66
|
const flowName = useDeviceFlow ? "device authorization" : "PKCE (browser)";
|
|
68
67
|
console.log(pc.gray(` Using ${flowName} flow`));
|
|
69
|
-
console.log(pc.cyan(`\n Step 2/4: Authenticating with
|
|
68
|
+
console.log(pc.cyan(`\n Step 2/4: Authenticating with IdP (${flowName})...`));
|
|
70
69
|
let accessToken;
|
|
71
70
|
const oauthOpts = {
|
|
72
71
|
issuer,
|
|
73
|
-
clientId
|
|
74
|
-
projectId: projectId || void 0
|
|
72
|
+
clientId
|
|
75
73
|
};
|
|
76
74
|
if (useDeviceFlow) accessToken = await deviceFlow(oauthOpts);
|
|
77
75
|
else accessToken = await pkceFlow(oauthOpts);
|
package/dist/commands/status.js
CHANGED
|
@@ -15,7 +15,7 @@ import { formatDuration, logger, toErrorMessage } from "@kici-dev/shared";
|
|
|
15
15
|
* Looks up local history first, then fetches from the orchestrator for
|
|
16
16
|
* up-to-date status and logs.
|
|
17
17
|
*/
|
|
18
|
-
const CLI_VERSION = "0.1.
|
|
18
|
+
const CLI_VERSION = "0.1.6";
|
|
19
19
|
/**
|
|
20
20
|
* Show status and details of a test run.
|
|
21
21
|
*
|
|
@@ -14,7 +14,7 @@ import { pathToFileURL } from "node:url";
|
|
|
14
14
|
* in its sandbox process). No Rolldown bundling: host-repo imports and
|
|
15
15
|
* transitive deps with dynamic import() resolve via Node's normal ESM loader
|
|
16
16
|
* against the workspace's node_modules — the same module graph any other
|
|
17
|
-
* `
|
|
17
|
+
* `pnpm exec tsx` invocation would see. This keeps ops-style workflows (which
|
|
18
18
|
* import repo-local modules like scripts/lib/*) working the same as minimal
|
|
19
19
|
* workflows that only touch @kici-dev/sdk.
|
|
20
20
|
*/
|
|
@@ -449,6 +449,41 @@ The lock file approach means the orchestrator stays git-agnostic -- it only need
|
|
|
449
449
|
|
|
450
450
|
---
|
|
451
451
|
|
|
452
|
+
## 5-minute quickstart
|
|
453
|
+
|
|
454
|
+
Source: https://kici.dev/docs/user/quickstart/
|
|
455
|
+
|
|
456
|
+
KiCI offers two equally-supported quickstart paths. Pick the one that fits your machine — both end with the same working pipeline (orchestrator + agent + your first workflow run visible in the dashboard).
|
|
457
|
+
|
|
458
|
+
## Option A — Docker / Podman (recommended)
|
|
459
|
+
|
|
460
|
+
Two containers brought up with `docker compose up -d` (orchestrator + PostgreSQL), plus one short-lived agent container spawned per job by the container scaler. Minimal host setup, perfect for a laptop, home server, or a tiny VM. No need to install PostgreSQL or any other system service.
|
|
461
|
+
|
|
462
|
+
[Start with the Docker / Podman quickstart →](./quickstart/compose.md)
|
|
463
|
+
|
|
464
|
+
## Option B — Bare-metal install
|
|
465
|
+
|
|
466
|
+
Native systemd services managed by `kici-admin orchestrator install` / `kici-admin agent install` — the orchestrator and agents run as native processes. The backing PostgreSQL runs as a single container by default (one `docker compose up -d`), or you can install it natively if you'd rather not run a container runtime at all. Best for a long-lived Linux host.
|
|
467
|
+
|
|
468
|
+
[Start with the bare-metal quickstart →](./quickstart/bare-metal.md)
|
|
469
|
+
|
|
470
|
+
## Which should I pick?
|
|
471
|
+
|
|
472
|
+
| | Docker / Podman | Bare metal |
|
|
473
|
+
| ----------------- | ---------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
474
|
+
| Host requirements | `docker` or `podman` with compose v2.20+ | systemd, Node.js 24+, PostgreSQL 18 (container — needs `docker`/`podman` — or native) |
|
|
475
|
+
| Time to first run | ~5 minutes | ~10 minutes |
|
|
476
|
+
| Upgrades | `docker compose pull` + restart | `kici-admin orchestrator restart` after `npm install -g kici-admin@latest` |
|
|
477
|
+
| Best for | Quick evaluation, ephemeral hosts | Long-lived production hosts |
|
|
478
|
+
|
|
479
|
+
If you're not sure, pick Docker / Podman.
|
|
480
|
+
|
|
481
|
+
## Looking for the laptop-only path?
|
|
482
|
+
|
|
483
|
+
Both quickstarts deploy a real orchestrator + agent. If you only want to write a workflow and dry-run it on your laptop with no infrastructure, [Getting started](./getting-started.md) covers `kici test` and `kici run local` instead.
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
452
487
|
# Workflow patterns
|
|
453
488
|
|
|
454
489
|
## Basic workflow patterns
|
|
@@ -1337,7 +1372,7 @@ export default workflow('on-github-repo-push', {
|
|
|
1337
1372
|
- No auto-clone — `packages/agent/src/checkout/git-clone.ts` uses GitHub App installation tokens to fetch the repo; a generic source has none. Either set `checkout: false` and clone yourself with a PAT/Deploy Key secret (same pattern as the Forgejo manual-clone example above), or keep the workflow self-contained.
|
|
1338
1373
|
- No lock-file fetch — the orchestrator cannot fetch `.kici/kici.lock.json` at the pushed SHA via the GitHub API. The workflow must be pre-registered via the [registration model](../events.md#the-registration-model); ad-hoc per-commit workflow discovery that a GitHub App push gives you is not available.
|
|
1339
1374
|
- No changed-files enrichment — `event.changedFiles` is empty. Use JSONPath `match` on `rawPayload.commits[*].added/modified/removed` if you need path filters.
|
|
1340
|
-
- No check-run integration — KiCI cannot post
|
|
1375
|
+
- No check-run integration — KiCI cannot post Check Run results back to GitHub.
|
|
1341
1376
|
- Workflow authors must use `genericWebhook()`, not `push()` / `pr()` / `webhook()` — the latter three only match events delivered through the native GitHub App provider.
|
|
1342
1377
|
|
|
1343
1378
|
**When to use it anyway:** trigger-only workflows that don't need the cloned repo — posting Slack messages, kicking off external deploys, forwarding to downstream systems, or exposing GitHub repo events as `genericWebhook` for same-org [cross-source fan-out](../../architecture/webhooks/webhook-delivery.md#cross-source-delivery). For anything that compiles, tests, or checks code, install the GitHub App instead.
|
|
@@ -1390,7 +1425,7 @@ const build = step('build', {
|
|
|
1390
1425
|
|
|
1391
1426
|
## Examples repository
|
|
1392
1427
|
|
|
1393
|
-
For more runnable examples, see the [examples/](https://github.com/kici-dev/kici/tree/
|
|
1428
|
+
For more runnable examples, see the [examples/](https://github.com/kici-dev/kici-public/tree/main/examples) directory in the KiCI repository.
|
|
1394
1429
|
|
|
1395
1430
|
## GitHub check run output
|
|
1396
1431
|
|
|
@@ -3452,7 +3487,7 @@ function genericWebhook(config: GenericWebhookConfigInput): GenericWebhookTrigge
|
|
|
3452
3487
|
|
|
3453
3488
|
```typescript
|
|
3454
3489
|
interface GenericWebhookConfigInput {
|
|
3455
|
-
source: string; // Required:
|
|
3490
|
+
source: string; // Required: must match `--name` from `kici-admin source add generic`
|
|
3456
3491
|
events?: string[]; // Filter by event types
|
|
3457
3492
|
match?: Record<string, unknown>; // JSONPath payload matching
|
|
3458
3493
|
not?: Record<string, unknown>; // Negative JSONPath filter
|
|
@@ -3873,7 +3908,7 @@ The KiCI CLI supports three authentication methods: browser-based OAuth (default
|
|
|
3873
3908
|
|
|
3874
3909
|
The default `kici login` flow:
|
|
3875
3910
|
|
|
3876
|
-
1. Opens your default browser to the KiCI identity provider
|
|
3911
|
+
1. Opens your default browser to the KiCI identity provider
|
|
3877
3912
|
2. You authenticate in the browser
|
|
3878
3913
|
3. The CLI receives a token via localhost callback
|
|
3879
3914
|
4. A personal access token (PAT) is created and stored locally
|
|
@@ -4012,20 +4047,20 @@ The Platform exposes a versioned REST API under `/api/v1/*`. The same endpoints
|
|
|
4012
4047
|
|
|
4013
4048
|
Every request to `/api/v1/*` carries an `Authorization: Bearer <token>` header. The Platform routes on the prefix:
|
|
4014
4049
|
|
|
4015
|
-
| Prefix | Token type
|
|
4016
|
-
| ----------- |
|
|
4017
|
-
| `kici_pat_` | Personal access token
|
|
4018
|
-
| `kici_sk_` | User API key
|
|
4019
|
-
| `kici_sa_` | Service account key
|
|
4020
|
-
| (other) |
|
|
4050
|
+
| Prefix | Token type | Created via | Scope |
|
|
4051
|
+
| ----------- | ----------------------------- | --------------------------------------- | ---------------- |
|
|
4052
|
+
| `kici_pat_` | Personal access token | `kici login` or dashboard | User (cross-org) |
|
|
4053
|
+
| `kici_sk_` | User API key | Dashboard → Settings → API keys | Org |
|
|
4054
|
+
| `kici_sa_` | Service account key | Dashboard → Settings → Service accounts | Org |
|
|
4055
|
+
| (other) | OIDC JWT or opaque OIDC token | OIDC login (browser SPA) | User (cross-org) |
|
|
4021
4056
|
|
|
4022
|
-
JWT and opaque OIDC tokens are validated against
|
|
4057
|
+
JWT and opaque OIDC tokens are validated against the configured OIDC issuer (JWKS for JWTs, the issuer's UserInfo endpoint for opaque ones). All `kici_*` tokens are validated by SHA-256 hash lookup against the Platform DB. See [RBAC: authentication methods](../architecture/security/rbac.md#authentication-methods) for the full model.
|
|
4023
4058
|
|
|
4024
4059
|
> **Note:** `kici_ok_` keys are **not** for the HTTP API — they authenticate orchestrator-to-Platform WebSocket connections only. Use `kici_sk_` (or `kici_pat_`) for HTTP calls.
|
|
4025
4060
|
|
|
4026
4061
|
### Permissions
|
|
4027
4062
|
|
|
4028
|
-
Tokens authenticate; RBAC authorizes. Every org-scoped route runs `orgContextMiddleware` (verifies you are a member of the target org) followed by `requirePermission(resource, level)`. The
|
|
4063
|
+
Tokens authenticate; RBAC authorizes. Every org-scoped route runs `orgContextMiddleware` (verifies you are a member of the target org) followed by `requirePermission(resource, level)`. The 14 resources and 5 levels are documented in [RBAC](../architecture/security/rbac.md#permission-model). User API keys carry their own permission matrix bounded above by the creator's effective permissions; PATs inherit the user's role permissions (or are capped further by their `scopes` field).
|
|
4029
4064
|
|
|
4030
4065
|
### Configurable surfaces
|
|
4031
4066
|
|
|
@@ -4232,6 +4267,8 @@ kici run local [event] [options]
|
|
|
4232
4267
|
| `--junit <path>` | none | Output JUnit XML result to file |
|
|
4233
4268
|
| `--debug` | `false` | Verbose internals |
|
|
4234
4269
|
| `--kici-dir <path>` | `.kici` | Path to .kici directory |
|
|
4270
|
+
| `--in-place` | `false` | Run against the real working directory instead of an isolated tmp checkout (see "Execution isolation" below) |
|
|
4271
|
+
| `--keep` | `false` | Always retain the isolated tmp checkout (default: keep only on failure) |
|
|
4235
4272
|
|
|
4236
4273
|
**Interactive workflow selection (`--pick` / `-p`):**
|
|
4237
4274
|
|
|
@@ -4265,6 +4302,26 @@ Coordination is local only — running the same workflow on two different machin
|
|
|
4265
4302
|
|
|
4266
4303
|
The `SIGTERM`-to-`SIGKILL` grace window defaults to 30 000 ms. Override it with the `KICI_LOCAL_LOCK_KILL_GRACE_MS` environment variable (positive integer, milliseconds) when iterating on workflows that need longer to clean up on cancellation.
|
|
4267
4304
|
|
|
4305
|
+
**Execution isolation:**
|
|
4306
|
+
|
|
4307
|
+
By default, `kici run local` executes steps inside an **isolated tmp checkout** rather than against your real working directory. Any file a step writes, builds, or deletes — and any `git` mutation a step performs — lands in that throwaway copy, so casual local runs never touch your tree.
|
|
4308
|
+
|
|
4309
|
+
What gets materialized into the isolated checkout has full parity with what `kici run remote` reconstructs: your current working tree minus gitignored files, with `.kiciignore` applied to local changes, over a real `.git` directory. Concretely, the checkout is built from a clone pinned to your current `HEAD`, with your local overlay (modified, staged, and untracked-but-not-ignored files) copied on top and locally-deleted files removed. Workflows that read git metadata work because the `.git` directory is present and pinned to your `HEAD`.
|
|
4310
|
+
|
|
4311
|
+
The path is logged at run start (for example, `running in /tmp/kici-run-ab12cd`) so you can inspect it.
|
|
4312
|
+
|
|
4313
|
+
Cleanup policy:
|
|
4314
|
+
|
|
4315
|
+
- On a fully successful run, the isolated checkout is removed.
|
|
4316
|
+
- On failure, it is retained and its path is logged so you can inspect the failed state.
|
|
4317
|
+
- `--keep` always retains it, even on success.
|
|
4318
|
+
|
|
4319
|
+
Set the `KICI_RUN_DIR` environment variable to place the isolated checkout under a base directory other than the system temp directory.
|
|
4320
|
+
|
|
4321
|
+
Secrets are always sourced from your real `.kici/` directory, not from the isolated checkout. Gitignored secret files (such as `.kici/.env.local` and `.kici/secrets.yaml`) are never copied into the checkout, so a step that reads a secret still gets it from the original location.
|
|
4322
|
+
|
|
4323
|
+
Pass `--in-place` to run against the real working directory instead — useful when you explicitly want in-tree execution. `--in-place` requires no git repository; the default isolated mode does, and fails with an actionable error pointing at `--in-place` when the directory is not a git repository.
|
|
4324
|
+
|
|
4268
4325
|
**Examples:**
|
|
4269
4326
|
|
|
4270
4327
|
```bash
|
|
@@ -4453,7 +4510,7 @@ kici test push --files src/index.ts --files README.md
|
|
|
4453
4510
|
|
|
4454
4511
|
Authenticate with KiCI via browser-based OAuth (default) or API key (`--token`).
|
|
4455
4512
|
|
|
4456
|
-
By default, `kici login` opens your browser for
|
|
4513
|
+
By default, `kici login` opens your browser for OIDC authentication using PKCE. In headless environments (SSH, CI, containers), it automatically switches to the RFC 8628 device authorization flow where you visit a URL and enter a code.
|
|
4457
4514
|
|
|
4458
4515
|
After OAuth, the CLI exchanges the OIDC token for a personal access token (PAT) stored in the config directory (`~/.kici/config` by default, overridable with `KICI_CONFIG_DIR`).
|
|
4459
4516
|
|
|
@@ -5318,7 +5375,7 @@ The lock file (`kici.lock.json`) is a JSON file with the following top-level fie
|
|
|
5318
5375
|
|
|
5319
5376
|
| Field | Description |
|
|
5320
5377
|
| --------------- | ------------------------------------------------------------------------------------------------------------------- |
|
|
5321
|
-
| `schemaVersion` | Lock file schema version (currently
|
|
5378
|
+
| `schemaVersion` | Lock file schema version (currently 12). Incremented on breaking format changes. |
|
|
5322
5379
|
| `source` | Reference to the source file and export (e.g., `{ file: “.kici/workflows/ci.ts”, export: “#default” }`). |
|
|
5323
5380
|
| `contentHash` | SHA-256 of the serialized lock file content (excluding itself). Changes when any workflow, trigger, or job changes. |
|
|
5324
5381
|
| `lockfileHash` | SHA-256 of `.kici/package-lock.json`, used as the dependency cache key. Omitted when no package lock file exists. |
|
|
@@ -6068,6 +6125,7 @@ The left sidebar provides persistent navigation across all org-scoped pages:
|
|
|
6068
6125
|
- **Secrets** -- secret scope management with environment bindings
|
|
6069
6126
|
- **Approval queue** -- held runs pending approval (shows a badge with pending count)
|
|
6070
6127
|
- **Activity** -- federated forensic log merging upstream tenant-plane mutations and orchestrator reads (`access_log`) into one chronological stream
|
|
6128
|
+
- **DLQ** -- dead-letter queue of internal events whose dispatch retries were exhausted (shows a badge with the current depth)
|
|
6071
6129
|
- **Settings** -- organization settings with tabbed sub-pages
|
|
6072
6130
|
|
|
6073
6131
|
The sidebar footer shows the WebSocket connection indicator, your user profile, UTC/local time toggle, theme toggle, and a collapse button.
|
|
@@ -6445,7 +6503,7 @@ Each member's linked provider accounts (e.g. GitHub) are also visible here.
|
|
|
6445
6503
|
|
|
6446
6504
|
<!-- help:settings-roles#settings -->
|
|
6447
6505
|
|
|
6448
|
-
Roles define granular permissions across
|
|
6506
|
+
Roles define granular permissions across 14 resource categories (runs, secrets, members, etc.) with 5 access levels: `none`, `read`, `read_payload`, `write`, `admin`.
|
|
6449
6507
|
|
|
6450
6508
|
Create custom roles to restrict what team members can do, or use the built-in **Owner** role for full access.
|
|
6451
6509
|
|
|
@@ -6521,6 +6579,16 @@ When you hit the cap, new relayed webhooks are rejected with `429 Plan limit rea
|
|
|
6521
6579
|
|
|
6522
6580
|
<!-- /help:settings-billing-relayed-webhooks -->
|
|
6523
6581
|
|
|
6582
|
+
<!-- help:settings-billing-currency#settings -->
|
|
6583
|
+
|
|
6584
|
+
Switch the prices shown on the tier cards between US dollars and euros. The choice you pick here is also the currency Stripe charges in when you click "Upgrade".
|
|
6585
|
+
|
|
6586
|
+
The default is detected from your browser language. EU, EFTA, and UK locales default to euros; everywhere else defaults to dollars.
|
|
6587
|
+
|
|
6588
|
+
Your choice persists in a 90-day cookie (`kici_pricing_currency`), so it survives across reloads and applies on every billing page.
|
|
6589
|
+
|
|
6590
|
+
<!-- /help:settings-billing-currency -->
|
|
6591
|
+
|
|
6524
6592
|
<!-- help:billing-payment-failure#settings -->
|
|
6525
6593
|
|
|
6526
6594
|
This banner appears when your organization's latest payment to Stripe has failed. Your subscription remains active during the retry period, but you should update your payment method promptly to avoid service interruption.
|
|
@@ -6549,6 +6617,23 @@ Click a row's run target to jump straight to the run detail page.
|
|
|
6549
6617
|
|
|
6550
6618
|
<!-- /help:activity-filters -->
|
|
6551
6619
|
|
|
6620
|
+
## DLQ
|
|
6621
|
+
|
|
6622
|
+
The DLQ (dead-letter queue) page lists internal events whose dispatch attempts were exhausted (or that hit a non-retryable error). Each row shows when the event landed in the DLQ, the event name, the attempt count, the failure reason, and the last error message.
|
|
6623
|
+
|
|
6624
|
+
<!-- help:dlq#dlq -->
|
|
6625
|
+
|
|
6626
|
+
The DLQ holds events your org emitted that could not be dispatched within the retry budget. The sidebar badge shows the current depth so you can spot a building backlog without opening the page.
|
|
6627
|
+
|
|
6628
|
+
Per-row actions (visible when you have `event_dlq:write`):
|
|
6629
|
+
|
|
6630
|
+
- **Retry:** clears the DLQ flag and re-publishes the event. A healthy orchestrator picks it up immediately.
|
|
6631
|
+
- **Discard:** permanently deletes the row. Use when the payload is corrupt or the routing target no longer exists.
|
|
6632
|
+
|
|
6633
|
+
Members with only `event_dlq:read` see the list but cannot retry or discard. Org owners have both actions by default.
|
|
6634
|
+
|
|
6635
|
+
<!-- /help:dlq -->
|
|
6636
|
+
|
|
6552
6637
|
<!-- help:settings-ci-trust#settings -->
|
|
6553
6638
|
|
|
6554
6639
|
CI trust policy controls how your organization handles PR-triggered runs from different contributor types. Configure the default trust level for unknown contributors and set per-member overrides to control who can run workflows with full secrets access.
|
|
@@ -6643,6 +6728,22 @@ For each endpoint you can:
|
|
|
6643
6728
|
|
|
6644
6729
|
<!-- /help:settings-webhooks -->
|
|
6645
6730
|
|
|
6731
|
+
<!-- help:settings-security-dashboard-policy#settings -->
|
|
6732
|
+
|
|
6733
|
+
Read-only view of the orchestrator's dashboard-write policy.
|
|
6734
|
+
|
|
6735
|
+
Each row toggles one mutating dashboard action — setting a secret, approving a held run, retrying a dead-lettered webhook, and so on. The orchestrator operator decides which actions stay on the dashboard and which become **CLI-only**. The dashboard cannot change the policy itself — that's the point: disabled actions stay out of the SaaS Platform's trust path.
|
|
6736
|
+
|
|
6737
|
+
Manage the policy with:
|
|
6738
|
+
|
|
6739
|
+
- **Show the full policy:** `kici-admin org-settings dashboard-writes show`
|
|
6740
|
+
- **Disable an operation:** `kici-admin org-settings dashboard-writes set --op <name>=false`
|
|
6741
|
+
- **Reset to permissive defaults:** `kici-admin org-settings dashboard-writes reset`
|
|
6742
|
+
|
|
6743
|
+
The summary strip at the top shows total / enabled / disabled counts plus whether your orchestrator is currently connected. A disconnected orchestrator means the page falls back to the cached policy from the most recent connection.
|
|
6744
|
+
|
|
6745
|
+
<!-- /help:settings-security-dashboard-policy -->
|
|
6746
|
+
|
|
6646
6747
|
<!-- help:settings-webhooks-delivery-log#settings -->
|
|
6647
6748
|
|
|
6648
6749
|
The delivery log shows recent webhook deliveries for an endpoint, including the HTTP status code, number of retry attempts, and the event payload.
|
|
@@ -6698,6 +6799,7 @@ The settings page (`/orgs/:customerId/settings`) uses a tabbed layout:
|
|
|
6698
6799
|
9. **Global workflows** -- org-level security knobs for cross-repo workflows (visible with `org_settings:read` permission)
|
|
6699
6800
|
10. **Webhooks** -- outbound webhook endpoint management with delivery logs and test ping
|
|
6700
6801
|
11. **Event log** -- inbound webhook delivery log (visible with `event_log:read` permission)
|
|
6802
|
+
12. **Security** -- read-only view of the orchestrator's dashboard-write policy matrix (visible with `org_settings:read` permission)
|
|
6701
6803
|
|
|
6702
6804
|
Audit-log-style entries are no longer a settings tab; they live on the dedicated **Activity** page accessible from the sidebar.
|
|
6703
6805
|
|
|
@@ -6793,6 +6895,28 @@ Organizations are the top-level container for your CI/CD resources. Each org has
|
|
|
6793
6895
|
|
|
6794
6896
|
<!-- /help:orgs-list -->
|
|
6795
6897
|
|
|
6898
|
+
<!-- help:orchestrators-list#orchestrators -->
|
|
6899
|
+
|
|
6900
|
+
The Orchestrators page lists every orchestrator currently connected to this org, keyed by **cluster name**. Each row shows:
|
|
6901
|
+
|
|
6902
|
+
- **Cluster** — the human-friendly cluster name set on the orch via `kici-admin cluster-name set <name>`, or an auto-generated `cluster-<6hex>` if no operator has renamed it.
|
|
6903
|
+
- **Role** — `coordinator` (talks to Platform directly) or `worker` (relays through a coordinator).
|
|
6904
|
+
- **Version**, **mode**, **routing keys**, and **last heartbeat**.
|
|
6905
|
+
|
|
6906
|
+
Click a cluster to drill into its per-orch surfaces (security policy, environments, secrets, DLQ, registrations, global workflows). Different clusters in the same org can have different settings — this page is the entry point that lets you pick which cluster you're configuring.
|
|
6907
|
+
|
|
6908
|
+
<!-- /help:orchestrators-list -->
|
|
6909
|
+
|
|
6910
|
+
<!-- help:orchestrators-scope#orchestrators -->
|
|
6911
|
+
|
|
6912
|
+
Every panel inside this view scopes to the named cluster. Settings shown here come from that orchestrator's own database — a sibling orchestrator in the same org may have a different security policy, different environments, and different secrets.
|
|
6913
|
+
|
|
6914
|
+
When the cluster shows **disconnected**, the orch is offline and its current state can't be queried. Most child pages will return 404 in that state; return to the orchestrator list to find a connected cluster.
|
|
6915
|
+
|
|
6916
|
+
To rename a cluster, run `kici-admin cluster-name set <new>` on the orchestrator host and restart the orch service so the new name reaches Platform on the next `source.register`.
|
|
6917
|
+
|
|
6918
|
+
<!-- /help:orchestrators-scope -->
|
|
6919
|
+
|
|
6796
6920
|
## Workflows
|
|
6797
6921
|
|
|
6798
6922
|
The workflows page (`/orgs/:customerId/workflows`) shows permanently registered workflows listening for events. It displays a filterable table with columns for workflow name, repository, trigger types, last triggered time, next fire time (for scheduled workflows), source repos, and actions.
|
|
@@ -6841,6 +6965,22 @@ The secrets page (`/orgs/:customerId/secrets`) provides a scope-centric view of
|
|
|
6841
6965
|
|
|
6842
6966
|
Permission-gated: `secrets:read` to view scopes, `secrets:write` to add or delete secrets, `environments:write` to modify environment bindings.
|
|
6843
6967
|
|
|
6968
|
+
### Where secrets live
|
|
6969
|
+
|
|
6970
|
+
Secret values are stored in the orchestrator's secret store and authorized through the orchestrator's RBAC. The dashboard surfaces secret **names** and scope membership for every secret regardless of where the value was entered.
|
|
6971
|
+
|
|
6972
|
+
Whether secret **values** can be set from the dashboard depends on the orchestrator's [dashboard-write policy](/operator/security/dashboard-write-policy):
|
|
6973
|
+
|
|
6974
|
+
- **Permissive (default):** the "Add secret" and "Edit value" controls accept plaintext directly in the dashboard. This is how a typical SaaS CI tool works and is the right default for small teams.
|
|
6975
|
+
- **`secrets.set` disabled by policy:** the controls render with a lock icon, grayed out. Hovering shows the exact `kici-admin secret set` invocation needed; a copy button puts it on the clipboard. The control is inert — the dashboard issues no mutating request. Use the CLI to enter values; the dashboard refreshes within ~30 seconds and shows the new secret name.
|
|
6976
|
+
|
|
6977
|
+
The policy state is visible at three layers in the UI:
|
|
6978
|
+
|
|
6979
|
+
- A **lock-icon prefix** on every disabled control, with a per-control CLI hint.
|
|
6980
|
+
- A **per-page banner** on any page containing at least one disabled operation, listing every disabled op on that page and its CLI equivalent.
|
|
6981
|
+
|
|
6982
|
+
The Security policy page (Settings → Security → Dashboard policy) renders the full 23-row read-only matrix with the current state and the `kici-admin` command for each row. The policy itself cannot be changed from the dashboard — the orchestrator operator manages it via `kici-admin org-settings dashboard-writes`. See [Dashboard-write policy](/operator/security/dashboard-write-policy) for the operator-side details.
|
|
6983
|
+
|
|
6844
6984
|
## Approval queue
|
|
6845
6985
|
|
|
6846
6986
|
The approval queue page (`/orgs/:customerId/approval-queue`) shows held runs that are pending approval. Runs can be held due to environment protection rules (required reviewers, wait timers). The page supports filtering by status (pending, approved, rejected, expired) and provides approve/reject actions for users with `environments:write` permission. Users with `environments:admin` permission can skip wait timers.
|
|
@@ -7067,7 +7207,7 @@ kici login --token <<< "$KICI_API_KEY"
|
|
|
7067
7207
|
Point the CLI to a self-hosted or testing OIDC provider:
|
|
7068
7208
|
|
|
7069
7209
|
```bash
|
|
7070
|
-
export KICI_OIDC_ISSUER=https://your-
|
|
7210
|
+
export KICI_OIDC_ISSUER=https://your-idp.example.com
|
|
7071
7211
|
export KICI_OIDC_CLIENT_ID=your-client-id
|
|
7072
7212
|
export KICI_OIDC_PROJECT_ID=your-project-id
|
|
7073
7213
|
export KICI_PLATFORM_URL=https://your-platform.example.com
|
|
@@ -7510,7 +7650,7 @@ genericWebhook({
|
|
|
7510
7650
|
|
|
7511
7651
|
**Config options:** `source` (required), `events`, `match`, `not`, `auth`, `path`, `description`.
|
|
7512
7652
|
|
|
7513
|
-
Generic webhook sources must be created by an operator
|
|
7653
|
+
The `source` field MUST match the `--name` that an operator passed to `kici-admin source add generic --name <name>` when the source was created — that string is the source's identifier in the orchestrator. Generic webhook sources must be created by an operator before events can be received; see [Operator guide: event routing](../operator/event-routing.md) for setup instructions.
|
|
7514
7654
|
|
|
7515
7655
|
### Schedule events
|
|
7516
7656
|
|
|
@@ -7658,7 +7798,7 @@ KiCI's event router delivers every accepted event with **at-least-once** semanti
|
|
|
7658
7798
|
is released on failure) and the event is automatically retried.
|
|
7659
7799
|
- The retry policy is exponential backoff with full jitter: base 5 s, cap 5 min,
|
|
7660
7800
|
up to 5 attempts before the event lands in the **DLQ** (dead-letter queue).
|
|
7661
|
-
Operators triage DLQ entries via `kici-admin event-dlq list / retry / discard`.
|
|
7801
|
+
Operators triage DLQ entries via `kici-admin event-dlq list / count / retry / discard`.
|
|
7662
7802
|
|
|
7663
7803
|
**What this means for workflow authors:**
|
|
7664
7804
|
|
|
@@ -8151,6 +8291,60 @@ Secrets are managed per-environment in the orchestrator (see [operator docs](/op
|
|
|
8151
8291
|
|
|
8152
8292
|
This design prevents accidental secret leakage through child processes, log output, or error messages. Only secrets you explicitly request are loaded into memory.
|
|
8153
8293
|
|
|
8294
|
+
## Where secret values come from
|
|
8295
|
+
|
|
8296
|
+
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.
|
|
8297
|
+
|
|
8298
|
+
### Default — dashboard or CLI
|
|
8299
|
+
|
|
8300
|
+
A fresh orchestrator starts in **permissive** mode: both surfaces are available.
|
|
8301
|
+
|
|
8302
|
+
- **Dashboard:** Settings → Secrets → pick a scope → enter the secret name and value.
|
|
8303
|
+
- **CLI:** `kici-admin secret set --scope <scope> <KEY>` against the orchestrator's HTTP admin API.
|
|
8304
|
+
|
|
8305
|
+
Use whichever fits the workflow — most small teams stay on the dashboard; ops engineers and CI scripts use the CLI.
|
|
8306
|
+
|
|
8307
|
+
### When the operator has disabled dashboard writes
|
|
8308
|
+
|
|
8309
|
+
The orchestrator operator can flip `secrets.set` (and `variables.set`) to **CLI-only** as part of the [dashboard-write policy](/operator/security/dashboard-write-policy). When that flip is on:
|
|
8310
|
+
|
|
8311
|
+
- The dashboard's "Add secret" / "Edit value" controls render with a lock icon. Clicking them shows a tooltip with the exact `kici-admin secret set` invocation needed.
|
|
8312
|
+
- The dashboard's secrets page still lists secret **names**, scopes, and bindings — only the value-entry path moves to the CLI.
|
|
8313
|
+
- `kici-admin secret set` becomes the single entry point for new and updated secret values.
|
|
8314
|
+
|
|
8315
|
+
This configuration is common for SOC2-prep and regulated workloads, where the customer requirement is "the SaaS control plane process never receives plaintext customer secret values." The dashboard remains usable for everything else (read paths, name CRUD, environment bindings).
|
|
8316
|
+
|
|
8317
|
+
### CLI input modes
|
|
8318
|
+
|
|
8319
|
+
`kici-admin secret set` accepts five input modes — pick the one that fits your workflow:
|
|
8320
|
+
|
|
8321
|
+
```bash
|
|
8322
|
+
# Interactive prompt (default when stdin is a TTY). No echo, no shell history.
|
|
8323
|
+
kici-admin secret set --scope production DB_PASSWORD --prompt
|
|
8324
|
+
|
|
8325
|
+
# Pipe from another tool (default when stdin is not a TTY).
|
|
8326
|
+
pass show prod/db | kici-admin secret set --scope production DB_PASSWORD --from-stdin
|
|
8327
|
+
|
|
8328
|
+
# Read from a file (handy after `sops -d` to a tmpfile).
|
|
8329
|
+
kici-admin secret set --scope production DB_PASSWORD --from-file ./db.pass
|
|
8330
|
+
|
|
8331
|
+
# Read from a named environment variable (CI-friendly).
|
|
8332
|
+
KICI_SECRET_VALUE=$(my-secrets-fetcher prod db) \
|
|
8333
|
+
kici-admin secret set --scope production DB_PASSWORD --from-env KICI_SECRET_VALUE
|
|
8334
|
+
|
|
8335
|
+
# Direct argv — discouraged. Prints a stderr warning ("visible in shell history").
|
|
8336
|
+
kici-admin secret set --scope production DB_PASSWORD --value "<plaintext>"
|
|
8337
|
+
```
|
|
8338
|
+
|
|
8339
|
+
Two cross-cutting flags help every mode:
|
|
8340
|
+
|
|
8341
|
+
- `--confirm-fingerprint <hex>` — pre-compute SHA-256 of the value and pass it. The CLI rejects the call if the value's fingerprint doesn't match. Catches paste corruption.
|
|
8342
|
+
- `--dry-run` — parse and validate the value, print `[dry-run] would set <key> in scope <scope> sha256=<hex>`, exit without writing.
|
|
8343
|
+
|
|
8344
|
+
`kici-admin variable set` uses the same flags for non-encrypted variables, plus `--locked` to mark a variable as immutable from subsequent dashboard writes.
|
|
8345
|
+
|
|
8346
|
+
A full reference of input modes — including the default-mode resolution rules and the security trade-offs of each — lives in [Dashboard-write policy → CLI input modes](/operator/security/dashboard-write-policy#cli-input-modes-for-the-plaintext-path).
|
|
8347
|
+
|
|
8154
8348
|
## Accessing secrets
|
|
8155
8349
|
|
|
8156
8350
|
Use `ctx.secrets.get(key)` to retrieve a secret value. The method is async to support process-level step isolation in future versions.
|
|
@@ -8399,11 +8593,14 @@ repos where you can't install an App.
|
|
|
8399
8593
|
https://<platform-host>/webhook/<orgId>/github
|
|
8400
8594
|
```
|
|
8401
8595
|
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8596
|
+
GitHub App webhooks are always delivered to this Platform endpoint and
|
|
8597
|
+
relayed to your orchestrator over its outbound connection — platform and
|
|
8598
|
+
hybrid orchestrators both receive GitHub events this way. Independent-mode
|
|
8599
|
+
orchestrators have no Platform connection and therefore no GitHub-App
|
|
8600
|
+
ingress; use a generic webhook source instead. The `<orgId>` segment is
|
|
8601
|
+
the KiCI organization ID the source belongs to; the `<appId>` is
|
|
8602
|
+
discovered from `X-GitHub-Hook-Installation-Target-ID` at request time and
|
|
8603
|
+
is _not_ part of the URL.
|
|
8407
8604
|
|
|
8408
8605
|
4. **Set the webhook secret.** Generate a random hex string (e.g.
|
|
8409
8606
|
`openssl rand -hex 32`) and save it for step 4 of the orchestrator
|
|
@@ -8412,18 +8609,38 @@ repos where you can't install an App.
|
|
|
8412
8609
|
|
|
8413
8610
|
5. **Pick permissions.** Minimum required:
|
|
8414
8611
|
|
|
8415
|
-
| Scope
|
|
8416
|
-
|
|
|
8417
|
-
| Repository -> Contents
|
|
8418
|
-
| Repository -> Metadata
|
|
8419
|
-
| Repository -> Pull requests
|
|
8420
|
-
| Repository -> Checks
|
|
8421
|
-
|
|
|
8612
|
+
| Scope | Access | Why |
|
|
8613
|
+
| --------------------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
8614
|
+
| Repository -> Contents | Read | Clone the repo to read the lock file |
|
|
8615
|
+
| Repository -> Metadata | Read (auto) | Default for every App; also lets KiCI look up a pull-request author's repository access level for CI trust |
|
|
8616
|
+
| Repository -> Pull requests | Read | Match `pull_request` triggers |
|
|
8617
|
+
| Repository -> Checks | Read & write | Post KiCI's enriched Check runs |
|
|
8618
|
+
| Organization -> Members | Read | (optional, org installs) Receive `organization` / `membership` / `team` events so KiCI's CI-trust permission cache invalidates promptly on access changes |
|
|
8619
|
+
|
|
8620
|
+
The first four rows cover the core flow (clone, trigger matching,
|
|
8621
|
+
Check runs). The **Organization -> Members** row is only relevant if
|
|
8622
|
+
you use [CI trust tiers](../../architecture/security/ci-security.md)
|
|
8623
|
+
on an org-level install — see the event note below.
|
|
8422
8624
|
|
|
8423
8625
|
6. **Subscribe to events.** At minimum: `push`, `pull_request`,
|
|
8424
8626
|
`check_run`, `check_suite`. Add others (`issues`, `release`, ...) if
|
|
8425
8627
|
your workflows use those triggers.
|
|
8426
8628
|
|
|
8629
|
+
**For CI trust (optional but recommended on org installs):** also
|
|
8630
|
+
subscribe to `member`, `organization`, `membership`, and `team`.
|
|
8631
|
+
KiCI caches each pull-request author's repository access level (used
|
|
8632
|
+
to decide whether workflow changes take effect immediately or are
|
|
8633
|
+
held for approval — see
|
|
8634
|
+
[CI security](../../architecture/security/ci-security.md)). These
|
|
8635
|
+
events let the orchestrator drop stale cache entries the moment a
|
|
8636
|
+
contributor's access changes. They are not required for correctness:
|
|
8637
|
+
without them the cache simply ages out on its own 15-minute TTL, so a
|
|
8638
|
+
permission change can take up to 15 minutes to take effect. The
|
|
8639
|
+
`organization` / `membership` / `team` events require the
|
|
8640
|
+
**Organization -> Members** read permission and an org-level
|
|
8641
|
+
installation; `member` is a repository event covered by the default
|
|
8642
|
+
Metadata permission.
|
|
8643
|
+
|
|
8427
8644
|
7. **Generate a private key.** Scroll to the bottom of the App settings
|
|
8428
8645
|
and click _Generate a private key_. A `.pem` file downloads —
|
|
8429
8646
|
store it safely; you cannot redownload it.
|
|
@@ -8449,10 +8666,21 @@ kici-admin --url http://<orchestrator-host>:4000 --token $KICI_BOOTSTRAP_ADMIN_T
|
|
|
8449
8666
|
--webhook-secret <the-webhook-secret-from-step-4>
|
|
8450
8667
|
```
|
|
8451
8668
|
|
|
8452
|
-
The command
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8669
|
+
The command prints the routing key (always `github:<appId>`) and the public
|
|
8670
|
+
webhook URL to paste into the GitHub App's "Webhook URL" field:
|
|
8671
|
+
|
|
8672
|
+
```
|
|
8673
|
+
Source added: github:<appId> (my-org)
|
|
8674
|
+
Webhook URL: https://<platform-host>/webhook/<orgId>/github
|
|
8675
|
+
↳ Paste this into your GitHub App's "Webhook URL" field.
|
|
8676
|
+
```
|
|
8677
|
+
|
|
8678
|
+
When the orchestrator runs in independent mode (no Platform connection) the
|
|
8679
|
+
URL line reads `(unavailable — this orchestrator runs in independent mode)`,
|
|
8680
|
+
because GitHub-App ingress is Platform-relayed. The private key and webhook
|
|
8681
|
+
secret are stored encrypted in the orchestrator database under
|
|
8682
|
+
`KICI_SECRET_KEY`; no restart needed — the orchestrator accepts webhooks from
|
|
8683
|
+
this App immediately.
|
|
8456
8684
|
|
|
8457
8685
|
**Secret input modes** (for `--private-key` and `--webhook-secret`):
|
|
8458
8686
|
|
|
@@ -9529,13 +9757,13 @@ GitHub Platform Orchestrator Agent
|
|
|
9529
9757
|
|
|
9530
9758
|
5. **Agent execution:** The agent wraps each `onJobDispatch` callback in `requestContext.run()` with `requestId`, `runId`, and `jobId`. A trace header is printed once at job start. All subsequent log lines carry all trace fields automatically.
|
|
9531
9759
|
|
|
9532
|
-
6. **Check run summaries:** GitHub Check Run updates include `Trace: <requestId> | Run: <runId>` in the summary text, giving operators a direct link from GitHub UI to
|
|
9760
|
+
6. **Check run summaries:** GitHub Check Run updates include `Trace: <requestId> | Run: <runId>` in the summary text, giving operators a direct link from GitHub UI to Loki queries.
|
|
9533
9761
|
|
|
9534
9762
|
### Implementation
|
|
9535
9763
|
|
|
9536
|
-
Trace propagation uses Node.js `AsyncLocalStorage` from `@kici-dev/shared`. A logger format
|
|
9764
|
+
Trace propagation uses Node.js `AsyncLocalStorage` from `@kici-dev/shared`. A logger format reads the current context and injects fields into every JSON log line -- no changes needed at individual call sites.
|
|
9537
9765
|
|
|
9538
|
-
Tier identification is handled at the infrastructure level: `
|
|
9766
|
+
Tier identification is handled at the infrastructure level: the `service` Loki label (set by Grafana Alloy from the systemd unit / log source) identifies which service produced the log (`platform`, `orchestrator`, `agent`, etc.). For agent logs forwarded through the orchestrator's stdout, the parsed JSON also carries an inner `service: 'agent'` field — query both with `{service="orchestrator"} | json | service="agent"` to disambiguate.
|
|
9539
9767
|
|
|
9540
9768
|
## Output chaining data flow
|
|
9541
9769
|
|
|
@@ -9633,7 +9861,7 @@ The Platform tier exposes a `/ws/browser` WebSocket endpoint for dashboard clien
|
|
|
9633
9861
|
- [State machine](./execution/state-machine.md) -- job execution state transitions
|
|
9634
9862
|
- [Webhook delivery](./webhooks/webhook-delivery.md) -- detailed webhook processing pipeline
|
|
9635
9863
|
- [Operator: dependency caching](../operator/dependency-caching.md) -- configuration guide
|
|
9636
|
-
- [Operator: monitoring & tracing](../operator/observability/monitoring.md) -- trace fields and
|
|
9864
|
+
- [Operator: monitoring & tracing](../operator/observability/monitoring.md) -- trace fields and Loki queries
|
|
9637
9865
|
- [Operator: event routing & generic webhooks](../operator/event-routing.md) -- generic source setup and trust management
|
|
9638
9866
|
- [SDK reference: output chaining](../user/sdk/core.md#output-chaining) -- user-facing output chaining API
|
|
9639
9867
|
|
|
@@ -9693,7 +9921,7 @@ Per-source secrets enable multi-tenant Platform with proper isolation. Each cust
|
|
|
9693
9921
|
|
|
9694
9922
|
**Decision:** Webhooks are routed by provider-scoped routing key (e.g., `github:12345`) derived from the `X-GitHub-Hook-Installation-Target-ID` header. One routing key maps to one orchestrator connection.
|
|
9695
9923
|
|
|
9696
|
-
App ID routing provides a clean 1:1 mapping between a customer's GitHub App and their orchestrator. The orchestrator extracts the `installation_id` from the webhook payload body for GitHub API calls (fetching lock files,
|
|
9924
|
+
App ID routing provides a clean 1:1 mapping between a customer's GitHub App and their orchestrator. The orchestrator extracts the `installation_id` from the webhook payload body for GitHub API calls (fetching lock files, posting check runs).
|
|
9697
9925
|
|
|
9698
9926
|
**Alternative:** Route by Installation ID (more granular, one App can have many installations). Rejected because it adds complexity without clear benefit -- most customers use one App with one or a few installations, and the orchestrator can handle multiple installations internally.
|
|
9699
9927
|
|
|
@@ -9885,7 +10113,7 @@ Shared utilities used across packages. Provides `initZx()` for zx initialization
|
|
|
9885
10113
|
|
|
9886
10114
|
### Dashboard
|
|
9887
10115
|
|
|
9888
|
-
Web UI for KiCI. A browser single-page application that provides the operator dashboard with execution run listing, run detail views, real-time log streaming, settings management, and keyboard shortcut support. Authenticates via OIDC against
|
|
10116
|
+
Web UI for KiCI. A browser single-page application that provides the operator dashboard with execution run listing, run detail views, real-time log streaming, settings management, and keyboard shortcut support. Authenticates via OIDC against the identity provider and communicates with the Platform REST-over-WebSocket API.
|
|
9889
10117
|
|
|
9890
10118
|
### `kici` (wrapper)
|
|
9891
10119
|
|
|
@@ -9961,7 +10189,7 @@ The agent connects outbound to the orchestrator WebSocket endpoint. After regist
|
|
|
9961
10189
|
|
|
9962
10190
|
## Authentication and multi-tenancy
|
|
9963
10191
|
|
|
9964
|
-
KiCI uses application-level tenant isolation. The Platform dashboard API accepts three authentication methods (PATs, API keys, JWTs) and enforces org membership on every `/api/v1/orgs/:customerId/*` request
|
|
10192
|
+
KiCI uses application-level tenant isolation. The Platform dashboard API accepts three authentication methods (PATs, API keys, JWTs) and enforces org membership on every `/api/v1/orgs/:customerId/*` request.
|
|
9965
10193
|
|
|
9966
10194
|
## See also
|
|
9967
10195
|
|