> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mindfort.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD

> Learn how to run MindFort security assessments and tasks from CI/CD pipelines, with GitHub Actions examples for assessments, tasks, and templates.

Integrate MindFort into your CI/CD pipelines to automatically trigger security assessments and tasks on every push, pull request, or deployment. This ensures your applications are continuously tested for vulnerabilities as part of your development workflow.

## Prerequisites

Before configuring your pipeline, you'll need:

1. **API Key** — Generate one from the [MindFort Dashboard](https://cloud.mindfort.app) under **Settings > API Keys**.
2. **Target ID** — Find this in **Target Inventory** by clicking on the target you want to assess.
3. **Template ID** *(optional)* — For templated tasks, find this under **Agents > Templates**.

Store your API key as a secret in your CI/CD platform — never commit it to your repository.

## GitHub Actions Examples

### Trigger an Assessment

Runs a security assessment against your target on every push or PR to `main`. Configure the assessment method with the `MINDFORT_ASSESSMENT_METHOD` variable (`turbo`, `balanced`, or `deep`). These API values map to the dashboard labels **Balanced**, **Deep**, and **Ultra**, respectively.

```yaml theme={null}
name: MindFort Security Assessment

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  mindfort-assessment:
    name: Trigger MindFort Assessment
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Assessment
        id: trigger
        run: |
          RESPONSE=$(curl -s -w "\n%{http_code}" \
            -X POST "https://api.mindfort.app/v1/assessments/run" \
            -H "Authorization: Bearer ${{ secrets.MINDFORT_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "target_id": "${{ vars.MINDFORT_TARGET_ID }}",
              "assessment_method": "${{ vars.MINDFORT_ASSESSMENT_METHOD || 'turbo' }}"
            }')

          HTTP_CODE=$(echo "$RESPONSE" | tail -1)
          BODY=$(echo "$RESPONSE" | sed '$d')

          echo "status_code=$HTTP_CODE" >> "$GITHUB_OUTPUT"
          echo "response=$BODY" >> "$GITHUB_OUTPUT"

          if [ "$HTTP_CODE" -ne 200 ]; then
            echo "::error::MindFort API returned HTTP $HTTP_CODE: $BODY"
            exit 1
          fi

          ASSESSMENT_ID=$(echo "$BODY" | jq -r '.assessment_id')
          echo "assessment_id=$ASSESSMENT_ID" >> "$GITHUB_OUTPUT"
          echo "Assessment triggered: $ASSESSMENT_ID"

      - name: Summary
        if: always()
        run: |
          echo "### MindFort Assessment" >> "$GITHUB_STEP_SUMMARY"
          if [ "${{ steps.trigger.outputs.assessment_id }}" != "" ]; then
            echo "- **Assessment ID:** \`${{ steps.trigger.outputs.assessment_id }}\`" >> "$GITHUB_STEP_SUMMARY"
            echo "- **Status:** Triggered" >> "$GITHUB_STEP_SUMMARY"
          else
            echo "- **Status:** Failed (HTTP ${{ steps.trigger.outputs.status_code }})" >> "$GITHUB_STEP_SUMMARY"
          fi
```

<Accordion title="Required secrets and variables">
  | Type     | Name                         | Description                                         |
  | -------- | ---------------------------- | --------------------------------------------------- |
  | Secret   | `MINDFORT_API_KEY`           | Your MindFort API key                               |
  | Variable | `MINDFORT_TARGET_ID`         | UUID of the target to assess                        |
  | Variable | `MINDFORT_ASSESSMENT_METHOD` | Optional — `turbo` (default), `balanced`, or `deep` |
</Accordion>

### List Targets and Findings

Use the organization-wide endpoints when you want to discover targets first, then list findings across all targets or within one target. These endpoints use `limit` and `offset` pagination and include a `total` count.

```bash theme={null}
curl -G "https://api.mindfort.app/v1/targets" \
  -H "Authorization: Bearer ${MINDFORT_API_KEY}" \
  --data-urlencode "limit=25"
```

```bash theme={null}
curl -G "https://api.mindfort.app/v1/findings" \
  -H "Authorization: Bearer ${MINDFORT_API_KEY}" \
  --data-urlencode "target_id=${MINDFORT_TARGET_ID}" \
  --data-urlencode "status=ACTIVE" \
  --data-urlencode "exclude_secured=true" \
  --data-urlencode "severity=critical" \
  --data-urlencode "sort_by=severity" \
  --data-urlencode "limit=25"
```

`GET /v1/findings` returns finding summaries with `id`, `title`, `severity`, `severity_score`, `status`, `created_at`, and `target_id`. Defaults to `status=ACTIVE`; set `exclude_secured=true` to match the dashboard Open tab (vulnerabilities only). Use `assessment_id` to scope to one assessment run. See [Findings API](/api-reference/findings) for all filters.

Use `GET /v1/findings/{finding_id}` to fetch full details, including `description`, `impact`, `evidence`, `approach`, and `remediation_advice`.

### Cancel an Assessment

Use the `assessment_id` returned by `POST /v1/assessments/run` or copied from the Assessments page.

```bash theme={null}
curl -X POST "https://api.mindfort.app/v1/assessments/${MINDFORT_ASSESSMENT_ID}/cancel" \
  -H "Authorization: Bearer ${MINDFORT_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{}'
```

### Update Finding Status

Use status updates to keep triage state in sync from automation.

```bash theme={null}
curl -X POST "https://api.mindfort.app/v1/findings/${MINDFORT_FINDING_ID}/status" \
  -H "Authorization: Bearer ${MINDFORT_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"status":"RESOLVED"}'
```

Valid status values are `ACTIVE`, `RESOLVED`, and `ARCHIVED`.

### Start a New Task

Runs a custom security task with a natural-language instruction against your target.

```yaml theme={null}
name: MindFort Security Task

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  mindfort-task:
    name: Run MindFort Task
    runs-on: ubuntu-latest
    steps:
      - name: Start Task
        id: task
        run: |
          RESPONSE=$(curl -s -w "\n%{http_code}" \
            -X POST "https://api.mindfort.app/v1/tasks/run" \
            -H "Authorization: Bearer ${{ secrets.MINDFORT_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "target_id": "${{ vars.MINDFORT_TARGET_ID }}",
              "message": "${{ vars.MINDFORT_TASK_MESSAGE }}",
              "task_model": "${{ vars.MINDFORT_TASK_MODEL || 'MF1_FAST' }}"
            }')

          HTTP_CODE=$(echo "$RESPONSE" | tail -1)
          BODY=$(echo "$RESPONSE" | sed '$d')

          echo "status_code=$HTTP_CODE" >> "$GITHUB_OUTPUT"
          echo "response=$BODY" >> "$GITHUB_OUTPUT"

          if [ "$HTTP_CODE" -ne 200 ]; then
            echo "::error::MindFort API returned HTTP $HTTP_CODE: $BODY"
            exit 1
          fi

          TASK_ID=$(echo "$BODY" | jq -r '.task_id')
          echo "task_id=$TASK_ID" >> "$GITHUB_OUTPUT"
          echo "Task started: $TASK_ID"

      - name: Summary
        if: always()
        run: |
          echo "### MindFort Task" >> "$GITHUB_STEP_SUMMARY"
          if [ "${{ steps.task.outputs.task_id }}" != "" ]; then
            echo "- **Task ID:** \`${{ steps.task.outputs.task_id }}\`" >> "$GITHUB_STEP_SUMMARY"
            echo "- **Status:** Started" >> "$GITHUB_STEP_SUMMARY"
          else
            echo "- **Status:** Failed (HTTP ${{ steps.task.outputs.status_code }})" >> "$GITHUB_STEP_SUMMARY"
          fi
```

<Accordion title="Required secrets and variables">
  | Type     | Name                    | Description                                    |
  | -------- | ----------------------- | ---------------------------------------------- |
  | Secret   | `MINDFORT_API_KEY`      | Your MindFort API key                          |
  | Variable | `MINDFORT_TARGET_ID`    | UUID of the target to test                     |
  | Variable | `MINDFORT_TASK_MESSAGE` | Natural-language instruction for the task      |
  | Variable | `MINDFORT_TASK_MODEL`   | Optional — `MF1_FAST` (default) or `MF1_SMART` |
</Accordion>

Cancel a running task by passing the scoped `task_id` returned by the start endpoint:

```bash theme={null}
curl -X POST "https://api.mindfort.app/v1/tasks/${MINDFORT_TASK_ID}/cancel" \
  -H "Authorization: Bearer ${MINDFORT_API_KEY}" \
  -H "Content-Type: application/json"
```

### Start a Templated Task

Runs a pre-configured task template — no request body needed. Set up the template once in the MindFort dashboard and trigger it from your pipeline.

```yaml theme={null}
name: MindFort Templated Task

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  mindfort-templated-task:
    name: Run MindFort Templated Task
    runs-on: ubuntu-latest
    steps:
      - name: Start Templated Task
        id: task
        run: |
          RESPONSE=$(curl -s -w "\n%{http_code}" \
            -X POST "https://api.mindfort.app/v1/tasks/templates/${{ vars.MINDFORT_TEMPLATE_ID }}/run" \
            -H "Authorization: Bearer ${{ secrets.MINDFORT_API_KEY }}" \
            -H "Content-Type: application/json")

          HTTP_CODE=$(echo "$RESPONSE" | tail -1)
          BODY=$(echo "$RESPONSE" | sed '$d')

          echo "status_code=$HTTP_CODE" >> "$GITHUB_OUTPUT"
          echo "response=$BODY" >> "$GITHUB_OUTPUT"

          if [ "$HTTP_CODE" -ne 200 ]; then
            echo "::error::MindFort API returned HTTP $HTTP_CODE: $BODY"
            exit 1
          fi

          TASK_ID=$(echo "$BODY" | jq -r '.task_id')
          echo "task_id=$TASK_ID" >> "$GITHUB_OUTPUT"
          echo "Templated task started: $TASK_ID"

      - name: Summary
        if: always()
        run: |
          echo "### MindFort Templated Task" >> "$GITHUB_STEP_SUMMARY"
          if [ "${{ steps.task.outputs.task_id }}" != "" ]; then
            echo "- **Task ID:** \`${{ steps.task.outputs.task_id }}\`" >> "$GITHUB_STEP_SUMMARY"
            echo "- **Status:** Started" >> "$GITHUB_STEP_SUMMARY"
          else
            echo "- **Status:** Failed (HTTP ${{ steps.task.outputs.status_code }})" >> "$GITHUB_STEP_SUMMARY"
          fi
```

<Accordion title="Required secrets and variables">
  | Type     | Name                   | Description                      |
  | -------- | ---------------------- | -------------------------------- |
  | Secret   | `MINDFORT_API_KEY`     | Your MindFort API key            |
  | Variable | `MINDFORT_TEMPLATE_ID` | UUID of the task template to run |
</Accordion>

Templated task responses also return a scoped `task_id`; use that returned value when calling `POST /v1/tasks/{task_id}/cancel`.
