diff --git a/.mintlify/workflows/update-changelog.md b/.mintlify/workflows/update-changelog.md index ea7c1ed..0b67f62 100644 --- a/.mintlify/workflows/update-changelog.md +++ b/.mintlify/workflows/update-changelog.md @@ -5,6 +5,7 @@ on: context: - repo: "kosli-dev/cli" - repo: "kosli-dev/terraform-provider-kosli" + - repo: "kosli-dev/setup-cli-action" - repo: "kosli-dev/server" notify: slack: @@ -17,6 +18,7 @@ notify: Check each repository for **new tags** published since the last changelog entry for that product in changelog/index.mdx. Only document changes that are part of a tagged release — do not include unreleased work on `main`. - **kosli-dev/cli** and **kosli-dev/terraform-provider-kosli** use semver GitHub Releases (e.g., `v2.17.5`, `v0.6.3`). Check the Releases list for new versions. +- **kosli-dev/setup-cli-action** uses semver GitHub Releases (e.g., `v5.2.1`) with moving major/minor tags (`v5`, `v5.2`). Check the Releases list for new versions. **Most releases of this action are Dependabot or internal chore bumps** — only write a changelog entry when a release changes something user-facing: the action's inputs or outputs, its version-selection behavior, the supported runners, a breaking change (e.g., a changed default), or a bumped default Kosli CLI version worth calling out. Skip releases that are purely dependency bumps or internal chores. If several releases have accumulated since the last entry, consolidate their user-facing changes into a single entry keyed to the newest release. - **kosli-dev/server** does **not** use GitHub Releases. It uses timestamp-based git tags (e.g., `release-2026-04-30-10-56-05`). You must check git **tags** (not Releases) and look at the commits between the last covered tag and the most recent tag to identify user-facing changes. Consolidate all server changes since the last Platform changelog entry into a single entry. For each new release found, write a changelog entry in changelog/index.mdx. If no new tags exist for a repository since its last changelog entry, skip it. If there are no new tags across any repository, do not open a PR. @@ -27,6 +29,7 @@ Label should be the date the workflow runs, like "March 16, 2026". Description s Tags should be the product(s) affected by the release: - kosli-dev/cli → `["CLI"]` - kosli-dev/terraform-provider-kosli → `["Terraform Provider"]` +- kosli-dev/setup-cli-action → `["GitHub Action"]` - kosli-dev/server → `["Platform"]` The changelog is about changes to the product, not changes to the docs. diff --git a/.mintlify/workflows/update-github-action-reference.md b/.mintlify/workflows/update-github-action-reference.md new file mode 100644 index 0000000..5485a8f --- /dev/null +++ b/.mintlify/workflows/update-github-action-reference.md @@ -0,0 +1,38 @@ +--- +name: "Update GitHub Action reference" +on: + cron: "0 9 * * 1" +context: + - repo: "kosli-dev/setup-cli-action" +notify: + slack: + channels: + - docs +--- + +# Agent Instructions + +Check kosli-dev/setup-cli-action for **new tags/releases** published since the last time the GitHub Action reference page was updated. The action uses semver GitHub Releases (e.g., `v5.2.1`) with moving major/minor tags (`v5`, `v5.2`). Check the Releases list for new versions. Only consider changes that are part of a published release — do not include unreleased work on `main`. + +If no new releases exist since the last update, do not open a PR. + +Keep the GitHub Action reference in `github-action-reference/setup_cli_action.md` in sync with the action's [`README.md`](https://github.com/kosli-dev/setup-cli-action/blob/main/README.md) and [`action.yml`](https://github.com/kosli-dev/setup-cli-action/blob/main/action.yml), which are the source of truth. Update the page when any of the following change: + +1. **Inputs** — an input is added, removed, renamed, or its accepted values or default change (e.g., `version`, `github-token`). +2. **Outputs** — an output is added, removed, or its meaning changes (e.g., `version`). +3. **Version selection behavior** — how `latest`, full semver, and major/minor pins resolve. +4. **Supported runners** — the set of runners the action supports (`ubuntu-latest`, `windows-latest`, `macos-latest`). +5. **Usage** — the recommended major version in the `uses:` examples (e.g., `@v5`) or the example workflows. + +Most releases of this action are Dependabot or internal chore bumps. Those do not change the documented interface — if a release does not affect inputs, outputs, behavior, supported runners, or usage, do not open a PR for it. + +When updating the page: +- Follow Mintlify formatting conventions. Review the existing `github-action-reference/setup_cli_action.md` and other reference pages for style reference. +- Use root-relative links (e.g., `/integrations/ci_cd`, `/client_reference`). +- Keep the page a terse reference: inputs/outputs tables, version-selection rules, and usage examples. + +Do not modify changelog/index.mdx — that is handled by the "Update changelog" workflow. + +Before opening a PR, review all written content against the style rules in `styles/Kosli/`. In particular, `AmericanSpelling.yml` maps British spellings to their American equivalents — use American spelling throughout (e.g., "behavior", "customize", "organize"). + +PR titles and commit messages must follow the conventional commits format described in CLAUDE.md. Use `docs:` as the type. diff --git a/config/navigation.json b/config/navigation.json index 06a34ac..4b1d934 100644 --- a/config/navigation.json +++ b/config/navigation.json @@ -168,7 +168,7 @@ "group": "Integrations", "icon": "puzzle-piece", "pages": [ - "integrations/actions", + "integrations/kosli_actions", "integrations/ci_cd", "integrations/slack", "integrations/launchdarkly", @@ -455,45 +455,19 @@ } ] }, - { - "item": "Template Reference", - "icon": "file-code", - "groups": [ - { - "group": "Templates", - "pages": [ - "template-reference/flow_template" - ] - } - ] - }, - { - "item": "Policy Reference", - "icon": "scroll", - "groups": [ - { - "group": "Policies", - "pages": [ - "policy-reference/environment_policy", - "policy-reference/policy_builder", - "policy-reference/rego_policy" - ] - } - ] - }, { "item": "API Reference", "icon": "code", "openapi": "https://app.kosli.com/api/v2/openapi.json" }, { - "item": "Helm Reference", - "icon": "layer-group", + "item": "GitHub Action Reference", + "icon": "github", "groups": [ { - "group": "Helm Charts", + "group": "GitHub Action", "pages": [ - "helm/k8s_reporter" + "github-action-reference/setup_cli_action" ] } ] @@ -532,6 +506,44 @@ ] } ] + }, + { + "item": "Helm Reference", + "icon": "layer-group", + "groups": [ + { + "group": "Helm Charts", + "pages": [ + "helm/k8s_reporter" + ] + } + ] + }, + { + "item": "Template Reference", + "icon": "file-code", + "groups": [ + { + "group": "Templates", + "pages": [ + "template-reference/flow_template" + ] + } + ] + }, + { + "item": "Policy Reference", + "icon": "scroll", + "groups": [ + { + "group": "Policies", + "pages": [ + "policy-reference/environment_policy", + "policy-reference/policy_builder", + "policy-reference/rego_policy" + ] + } + ] } ] }, diff --git a/config/redirects.json b/config/redirects.json index a04693a..4518025 100644 --- a/config/redirects.json +++ b/config/redirects.json @@ -7,6 +7,10 @@ "source": "/tutorials/terraform_drift_detection", "destination": "/tutorials/detecting_non_terraform_changes" }, + { + "source": "/integrations/actions", + "destination": "/integrations/kosli_actions" + }, { "source": "/getting_started/approvals", "destination": "/getting_started/attestations" diff --git a/github-action-reference/setup_cli_action.md b/github-action-reference/setup_cli_action.md new file mode 100644 index 0000000..ef36e65 --- /dev/null +++ b/github-action-reference/setup_cli_action.md @@ -0,0 +1,120 @@ +--- +title: GitHub Action +description: Reference for the setup-kosli-cli GitHub Action that installs the Kosli CLI on GitHub Actions runners. +icon: github +--- + +The [`kosli-dev/setup-cli-action`](https://github.com/kosli-dev/setup-cli-action) GitHub Action (`setup-kosli-cli`) installs the [Kosli CLI](/client_reference) on GitHub Actions runners. After the action runs, every CLI command is available in later steps of the job. + +The action runs on `ubuntu-latest`, `windows-latest`, and `macos-latest` runners. + + +This page documents the action itself. For a broader guide to using Kosli in GitHub Actions, including the command flags that are defaulted from GitHub CI variables, see [CI/CD](/integrations/ci_cd). + + +## Usage + +Install the latest release of the Kosli CLI: + +```yaml +steps: + - uses: kosli-dev/setup-cli-action@v5 +``` + +Install a specific version: + +```yaml +steps: + - name: Setup Kosli CLI + uses: kosli-dev/setup-cli-action@v5 + with: + version: 2.11.43 +``` + +## Inputs + +| Input | Required | Default | Description | +| :--- | :--- | :--- | :--- | +| `version` | No | `latest` | Version of the Kosli CLI to install. See [Version selection](#version-selection). | +| `github-token` | No | `${{ github.token }}` | Token used to authenticate the GitHub API calls that resolve `latest` or a major/minor pin. You normally do not need to set this. | + +## Outputs + +| Output | Description | +| :--- | :--- | +| `version` | The resolved Kosli CLI version that was installed. When `version` is `latest` or a major/minor pin, this is the concrete semver that was selected (e.g. `2.12.0`). | + +Reference the resolved version in later steps: + +```yaml +steps: + - name: Setup Kosli CLI + id: setup + uses: kosli-dev/setup-cli-action@v5 + + - name: Print installed version + run: echo "Installed Kosli CLI ${{ steps.setup.outputs.version }}" +``` + +## Version selection + +The `version` input accepts: + +- **A full semver**, e.g. `2.11.43` — installed as-is. +- **A major pin**, e.g. `"2"` — resolves to the newest stable `2.x` release, and never `3.0.0`. +- **A major.minor pin**, e.g. `"2.11"` — resolves to the newest stable `2.11.z` patch. +- **`latest`** — resolves to the newest stable release of [`kosli-dev/cli`](https://github.com/kosli-dev/cli). This is the default. + +Major and minor pins resolve at runtime and never select a pre-release or a higher major. + + +Quote partial versions. In YAML, `version: 2.10` is parsed as the number `2.1`, which is not what you mean. Always quote a major or minor pin: `version: "2"`, `version: "2.10"`. + + +Track a major version and pick up every update within it without ever jumping to the next (breaking) major: + +```yaml +steps: + - name: Setup Kosli CLI + uses: kosli-dev/setup-cli-action@v5 + with: + version: "2" # newest stable 2.x, never 3.x +``` + +## Example job + +Secrets in GitHub Actions are not automatically exported as environment variables, so set the API token explicitly. All CLI flags can be set as environment variables by adding the `KOSLI_` prefix and capitalizing them. + +```yaml +jobs: + build-image: + runs-on: ubuntu-latest + env: + KOSLI_API_TOKEN: ${{ secrets.KOSLI_API_TOKEN }} + KOSLI_ORG: my-org + KOSLI_FLOW: my-flow + KOSLI_TRAIL: ${{ github.sha }} + IMAGE_NAME: my-registry/my-image:latest + steps: + - name: Build and push Docker image + id: build + uses: docker/build-push-action@v5 + with: + push: true + tags: ${{ env.IMAGE_NAME }} + + - name: Setup Kosli CLI + uses: kosli-dev/setup-cli-action@v5 + + - name: Attest image provenance + run: kosli attest artifact "${IMAGE_NAME}" --artifact-type=oci +``` + +For a complete example of a GitHub workflow using Kosli, see the Kosli CLI's [own workflow](https://github.com/kosli-dev/cli/blob/main/.github/workflows/docker.yml). + +## References + +- Action source: [`kosli-dev/setup-cli-action`](https://github.com/kosli-dev/setup-cli-action) +- Marketplace listing: [setup-kosli-cli](https://github.com/marketplace/actions/setup-kosli-cli) +- [CI/CD integration guide](/integrations/ci_cd) +- [Kosli CLI reference](/client_reference) diff --git a/integrations/ci_cd.md b/integrations/ci_cd.md index 67e5a6f..adb1b44 100644 --- a/integrations/ci_cd.md +++ b/integrations/ci_cd.md @@ -34,8 +34,8 @@ description: Use Kosli in CI Systems like GitHub Actions, GitLab CI, and more. ## Use Kosli in Github Actions - To use Kosli in [Github Actions](https://docs.github.com/en/actions) workflows, you can use the kosli [CLI setup action](https://github.com/marketplace/actions/setup-kosli-cli) to install the CLI on your Github Actions Runner. - Then, you can use all the [CLI commands](/client_reference) in your workflows. + To use Kosli in [Github Actions](https://docs.github.com/en/actions) workflows, you can use the [`setup-kosli-cli` GitHub Action](/github-action-reference/setup_cli_action) to install the CLI on your Github Actions Runner. + Then, you can use all the [CLI commands](/client_reference) in your workflows. See the GitHub Action reference for its inputs, outputs, and version-pinning options. ### GitHub Secrets diff --git a/integrations/actions.md b/integrations/kosli_actions.md similarity index 98% rename from integrations/actions.md rename to integrations/kosli_actions.md index 15cc211..04a18d7 100644 --- a/integrations/actions.md +++ b/integrations/kosli_actions.md @@ -31,7 +31,7 @@ To receive Kosli notifications in Slack, you have two options. You can either us - Create a [Slack incoming webhook](https://api.slack.com/messaging/webhooks#create_a_webhook). - - Use this webhook to [create a notification settings in the Kosli UI](/integrations/actions/#manage-actions-in-the-ui). + - Use this webhook to [create a notification settings in the Kosli UI](/integrations/kosli_actions/#manage-actions-in-the-ui). ## Custom Webhook Notifications diff --git a/tutorials/attest_snyk.md b/tutorials/attest_snyk.md index abd5f54..5ba2bed 100644 --- a/tutorials/attest_snyk.md +++ b/tutorials/attest_snyk.md @@ -112,4 +112,4 @@ You have run four types of Snyk scans and attested each result to a Kosli trail. From here you can: - Explore the trail in the [Kosli app](https://app.kosli.com) - Attest scans to an artifact in a trail — see [`kosli attest snyk`](/client_reference/kosli_attest_snyk) for details -- Add Snyk attestations to your CI pipeline using the [GitHub Actions integration](/integrations/actions) +- Add Snyk attestations to your CI pipeline using the [GitHub Action](/github-action-reference/setup_cli_action) diff --git a/tutorials/unauthorized_iac_changes.md b/tutorials/unauthorized_iac_changes.md new file mode 100644 index 0000000..691f5d8 --- /dev/null +++ b/tutorials/unauthorized_iac_changes.md @@ -0,0 +1,158 @@ +--- +title: "Detecting unauthorized Terraform changes" +description: "Learn how to use Kosli to detect unauthorized Terraform infrastructure changes — changes made outside your approved CI process." +--- + +By the end of this tutorial, you will have set up Kosli to track authorized Terraform changes and detect when an unauthorized change slips through. + + +This tutorial focuses on detecting changes made by bypassing the approved Terraform process (e.g. a developer running `terraform apply` directly from their machine). Detecting infrastructure drift is a separate concern covered by [Terraform drift detection](https://developer.hashicorp.com/terraform/tutorials/state/resource-drift). + + +## Prerequisites + +* [Install Terraform](https://developer.hashicorp.com/terraform/install). +* [Install Snyk CLI](https://docs.snyk.io/snyk-cli/getting-started-with-the-snyk-cli#install-the-snyk-cli-and-authenticate-your-machine) (optional — needed for the security scan step). +* [Install Kosli CLI](/getting_started/install). +* [Get a Kosli API token](/getting_started/authenticating_to_kosli). + +## Setup + +```shell +export KOSLI_ORG= +export KOSLI_API_TOKEN= +``` + +Clone the tutorial repository: + +```shell +git clone https://github.com/kosli-dev/iac-changes-tutorial.git +cd iac-changes-tutorial +``` + +## Create a Kosli flow + +Create a Kosli flow to represent the approved process for Terraform changes. Using --use-empty-template keeps things simple for this tutorial: + +```shell +kosli create flow tf-tutorial --use-empty-template +``` + +## Make and track an authorized change + + +In production, an authorized change goes through CI. In this tutorial, you run those commands locally to simulate the process. + + +Begin a trail to represent a single authorized change: + +```shell +kosli begin trail authorized-1 --flow=tf-tutorial +``` + +Optionally, scan your Terraform config for security issues and attest the SARIF output to Kosli: + +```shell +snyk iac test main.tf --sarif-file-output=sarif.json +kosli attest snyk --name=security --flow=tf-tutorial --trail=authorized-1 --scan-results=sarif.json +``` + +Create a Terraform plan, save it to a file, and attest it to Kosli: + +```shell +terraform init +terraform plan -out=tf.plan +kosli attest generic --name=tf-plan --flow=tf-tutorial --trail=authorized-1 --attachments=tf.plan +``` + +Apply the plan and attest the resulting state file as an artifact. Kosli calculates a fingerprint from the state file contents — this fingerprint is how it later detects unauthorized changes: + + +This tutorial uses a local state file for simplicity. In production, the state file is typically stored in cloud storage (e.g. AWS S3) and you would download it after the authorized change. Note that `--build-url` and `--commit-url` are set to placeholder URLs here — in CI these are set automatically. + + +```shell +terraform apply -auto-approve tf.plan +kosli attest artifact terraform.tfstate --name=state-file --artifact-type=file --flow=tf-tutorial --trail=authorized-1 \ + --build-url=https://example.com --commit-url=https://example.com --commit=HEAD +``` + +## Monitor the state file + +To detect unauthorized changes, Kosli monitors the state file for changes by tracking it in an environment. Create a `server` environment: + +```shell +kosli create env terraform-state --type=server +``` + +Report the current state file to the environment: + + +In production, configure environment reporting to run periodically or on state file changes. See [reporting AWS environments](/tutorials/report_aws_envs) if you use S3 as your Terraform backend. + + +```shell +kosli snapshot path terraform-state --name=tf-state --path=terraform.tfstate +``` + +Check the latest snapshot: + +```shell +kosli get snapshot terraform-state +``` + +You should see: + +```plaintext +COMMIT ARTIFACT FLOW COMPLIANCE RUNNING_SINCE REPLICAS +d881b2f Name: tf-state tf-tutorial COMPLIANT 28 minutes ago 1 + Fingerprint: a57667a7b921b91d438631afa1a1fe35300b4da909a19d2b61196580f30f1d0c +``` + +The `FLOW` column shows `tf-tutorial` — Kosli has provenance for this change. In the Kosli UI under **Environments > terraform-state**, the artifact shows as compliant. + +Environment shows an authorized change + +## Introduce an unauthorized change + +Simulate an unauthorized change by modifying line 6 of `main.tf` — change `random_pet_result` to `random_pet_name` — then apply directly without going through the approved process: + +```shell +terraform apply --auto-approve +``` + +Report the updated state file to Kosli: + + +In production this step is not needed — environment reporting runs automatically on change or on a schedule. + + +```shell +kosli snapshot path terraform-state --name=tf-state --path=terraform.tfstate +``` + +Check the snapshot again: + +```shell +kosli get snapshot terraform-state +``` + +You should see: + +```plaintext +COMMIT ARTIFACT FLOW COMPLIANCE RUNNING_SINCE REPLICAS +N/A Name: tf-state N/A NON-COMPLIANT 8 minutes ago 1 + Fingerprint: edd93dcde27718ed493222ceb218275655555f3f3bfefa95628c599e678ac325 +``` + +The `FLOW` is now `N/A` — Kosli has no provenance for this state file fingerprint. It was not attested through any known flow, which means the change was unauthorized. The environment page reflects this: + +Environment shows an unauthorized change + +## What you've accomplished + +You have used Kosli to track authorized Terraform changes and detect an unauthorized one. By fingerprinting the Terraform state file and comparing it against attested artifacts, Kosli can tell whether a running infrastructure state came from an approved process or not. + +From here you can: +* Set up alerts and automated responses when unauthorized changes are detected using [Kosli Actions](/integrations/kosli_actions) +* See how to report S3-backed state files automatically in the [Report AWS environments](/tutorials/report_aws_envs) tutorial