Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ stable enough to treat `krci` as a first-class agent tool.
| Area | What you get | Docs |
|---------------|----------------------------------------------------------------------------------|-------------------------------------------|
| Authentication | OIDC + PKCE browser flow, AES-256-GCM token storage, OS keyring integration | [`docs/auth.md`](docs/auth.md) |
| Projects | List and inspect projects, and build a project branch | [`docs/project.md`](docs/project.md) |
| Projects | List and inspect projects, list their built image versions, build a branch | [`docs/project.md`](docs/project.md) |
| Deployments | Inspect deployments, their apps, environments, and promotion gates | [`docs/deployment.md`](docs/deployment.md)|
| Environments | Inspect envs — deployed apps, infrastructure, gates, and health | [`docs/env.md`](docs/env.md) |
| Pipeline runs | List, filter, stream logs, and diagnose failures across Tekton runs | [`docs/pipelinerun.md`](docs/pipelinerun.md) |
Expand Down Expand Up @@ -117,7 +117,7 @@ start with the area you care about.
```
krci [--portal-url <url>]
auth login | status | logout
project list | get <name> | deployments <name> | build <name>
project list | get <name> | deployments <name> | versions <name> | build <name>
deployment list | get <name>
pipelinerun list | get <name> (also filters, --logs, --reason)
sonar list | get | gate | issues <project>
Expand Down
66 changes: 64 additions & 2 deletions docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,75 @@ Expires: 22 Apr 26 11:22 EEST (22h24m3s)
Groups: admin, developers, viewers
```

Exits non-zero when the token is missing or expired — handy for wrapping in a
shell guard:
### Exit codes

| State | Exit | Message (stderr) |
|-----------------------------------------|------|----------------------------------------------|
| Valid session | `0` | — |
| No stored session | `1` | `not authenticated: run 'krci auth login'` |
| Session expired and refresh not possible| `1` | `session expired: run 'krci auth login'` |
| `KRCI_TOKEN` is a JWT past its `exp` | `1` | `KRCI_TOKEN has expired: supply a fresh token` |
| `KRCI_TOKEN` or unreadable claims, portal rejects the token | `1` | `not authenticated: the portal rejected the token` |
| `KRCI_TOKEN` or unreadable claims, portal unreachable | `1` | `verifying the token with the portal: <cause>` |

The stored session comes from `krci auth login` and is checked locally.
`KRCI_TOKEN`, and a stored token whose claims cannot be read, are checked with
one call to the portal through the configured portal URL, so the check needs
the same configuration as every portal command: portal URL, cluster name, and
namespace. An `http://` portal URL for local development works as it does for
the other commands.

With `KRCI_TOKEN` set, `User`, `Groups`, and `Expires` come from its claims,
not from the stored session. When the portal accepts a token whose claims
cannot be read, such as an opaque OIDC access token, the command exits `0` and
prints `Status: Authenticated (unable to read user info)`; in JSON,
`data.user` is absent and `data.expiresAt` is `null`.

The non-zero exit makes the command a shell guard:

```bash
krci auth status >/dev/null 2>&1 || krci auth login
```

### JSON output

```bash
krci auth status -o json
```

```json
{
"schemaVersion": "1",
"data": {
"authenticated": true,
"user": "user@example.com",
"name": "User Name",
"groups": ["admin", "developers", "viewers"],
"expiresAt": "2026-04-22T08:22:00Z"
}
}
```

`groups` is always an array (`[]` when the token carries no groups);
`expiresAt` is RFC3339 in UTC, `null` when the token has no expiry; `user`
and `name` are omitted when the stored token's claims cannot be read.

Without a valid session the command still exits `1` and writes the error
envelope to stdout, so a script can branch on either signal:

```json
{
"schemaVersion": "1",
"error": { "message": "not authenticated: run 'krci auth login'" }
}
```

```bash
# Scripting — proceed only with a session that lasts another hour
krci auth status -o json |
jq -e '.data.expiresAt | fromdateiso8601 > (now + 3600)' >/dev/null || krci auth login
```

## `auth logout`

```bash
Expand Down
23 changes: 23 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,24 @@ Environment columns:
- **PROMOTE GATES** — number and type of quality gates that must pass
- **NAMESPACE** — target Kubernetes namespace

When the operator records `status.detailed_message` on the CDPipeline, a
`Message:` line follows `Available:`; stages with a message are listed under
a `Messages:` block below the table, `<env>: <message>` per line. Both are
absent for healthy resources.

```
Status: failed
Available: false
Message: failed to create namespace my-pipeline-dev: quota exceeded

Environments:
ORDER ENV DEPLOY MODE PROMOTE GATES NAMESPACE STATUS
0 dev Manual 1 manual my-pipeline-dev failed

Messages:
dev: failed to create namespace my-pipeline-dev: quota exceeded
```

## JSON output

```bash
Expand Down Expand Up @@ -91,6 +109,11 @@ krci deployment get my-pipeline -o json
}
```

`detailedMessage` appears on the deployment and on a stage only when the
resource carries `status.detailed_message` (`"status": "failed",
"detailedMessage": "failed to create namespace ...: quota exceeded"`);
`deployment list -o json` carries it on the same terms.

Agent workflow — list namespaces for a pipeline:

```bash
Expand Down
62 changes: 60 additions & 2 deletions docs/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,27 @@ The TTY view is layered top-to-bottom:

1. **Header** — `Environment / Deployment / Status / Description / Order`. Status
uses `output.StatusColor` (`created` → green, `failed` → red, `in_progress` → yellow).
A `Message` line follows `Status` when the Stage reports
`status.detailed_message`, the operator's reason behind a `failed` status.
2. **Infrastructure** — indented block with the Stage's static placement.
`Clean Pipeline: —` when no `cleanTemplate` is set.
3. **Quality Gates** — one bullet per gate; `autotests` gates show their
autotest name and branch (e.g. `autotests: smoke-tests (branch: main)`).
4. **Projects sub-table** — column order: `PROJECT`, `STATUS`, `SYNC`,
`VERSION`, `IMAGE_SHA`, `INGRESS`. Sorted by project name ascending.
5. **Conditions** — printed only when a project carries an Argo CD condition
or a sync operation that did not succeed:

```
Conditions (2):
- foo: ComparisonError: Failed to load live state: failed to get cluster info for "https://k8s.example.com": dial tcp: i/o timeout
- foo: operation Error: ComparisonError: Failed to load target state
```

This is where the reason behind an `unknown` or `degraded` status lives:
an unreachable target cluster, a chart that fails to render, a
`build/<version>` revision that does not exist. Multi-line messages are
collapsed to one row.

Projects sub-table semantics:

Expand Down Expand Up @@ -181,6 +196,7 @@ krci env get my-pipeline prod -o json
"deployment": "my-pipeline",
"env": "prod",
"status": "created",
"detailedMessage": null,
"description": "Production environment",
"order": 2,
"infrastructure": {
Expand All @@ -205,7 +221,34 @@ krci env get my-pipeline prod -o json
"ingressUrls": ["https://foo.prod.example.com"],
"argocdUrl": "/applications/my-pipeline-my-pipeline-prod-foo",
"deployedAt": "2026-04-25T08:00:00Z",
"valuesOverride": false
"valuesOverride": false,
"conditions": [],
"operation": {
"phase": "Succeeded",
"message": "successfully synced (all tasks run)",
"startedAt": "2026-04-25T07:59:40Z",
"finishedAt": "2026-04-25T08:00:00Z"
}
},
{
"name": "bar",
"status": "unknown",
"sync": "unknown",
"version": "2.0.1",
"imageTag": "2.0.1",
"imageDigest": null,
"ingressUrls": [],
"argocdUrl": "/applications/my-pipeline-my-pipeline-prod-bar",
"deployedAt": null,
"valuesOverride": false,
"conditions": [
{
"type": "ComparisonError",
"message": "Failed to load live state: failed to get cluster info for \"https://k8s.example.com\": dial tcp: i/o timeout",
"lastTransitionTime": "2026-04-25T08:03:12Z"
}
],
"operation": null
},
{
"name": "baz",
Expand All @@ -217,7 +260,9 @@ krci env get my-pipeline prod -o json
"ingressUrls": [],
"argocdUrl": null,
"deployedAt": null,
"valuesOverride": null
"valuesOverride": null,
"conditions": [],
"operation": null
}
]
}
Expand All @@ -227,10 +272,18 @@ krci env get my-pipeline prod -o json
Field absence rules:

- `description`, `cleanPipeline` → `null` when the Stage spec omits them.
- `detailedMessage` → the Stage's `status.detailed_message`, `null` when the
operator reported none.
- Per-project dynamic fields (`status`, `sync`, `version`, `imageTag`,
`imageDigest`, `argocdUrl`, `deployedAt`, `valuesOverride`) → `null` for
registered-but-not-deployed projects. `ingressUrls` is always an array,
`[]` when none.
- `conditions[]` is always an array, `[]` when the Application has none;
each entry carries `type`, `message`, and `lastTransitionTime` (`null`
when Argo CD omits it). `operation` → `null` for
registered-but-not-deployed projects and for Applications never synced;
otherwise `phase`, `message`, `startedAt`, `finishedAt`, each of the last
three `null` when absent.
- `qualityGates[]` is always an array (empty when none).
- In `-o json`, `imageDigest` is the FULL `sha256:...`. The table view
shortens it to 15 visible characters under `IMAGE_SHA`.
Expand All @@ -246,6 +299,11 @@ krci env get my-pipeline prod -o json |
krci env get my-pipeline prod -o json |
jq -r '.data.projects[] | select(.name=="foo") | .ingressUrls[]'

# Why is a project unknown or degraded? Argo CD conditions and the last operation
krci env get my-pipeline prod -o json |
jq -r '.data.projects[] | .name as $n | (.conditions[] | "\($n): \(.type): \(.message)"),
(select(.operation != null and .operation.phase != "Succeeded") | "\($n): operation \(.operation.phase): \(.operation.message)")'

# Quality-gate names + branches
krci env get my-pipeline prod -o json |
jq -r '.data.qualityGates[] | "\(.type): \(.stepName) (\(.branchName // "no-branch"))"'
Expand Down
Loading
Loading