From d97eb885e8286709755df79c82c8dbc75524a6c3 Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Wed, 30 Sep 2026 01:13:08 +0000 Subject: [PATCH 1/5] Align security product onboarding with current CLI and service contracts --- .github/workflows/snippet-tests.yml | 3 +- docs/6-developer-guide/sdks/python-sdk.md | 47 ++++++++- docs/cloud-security/api-reference.md | 8 +- docs/cloud-security/cli.md | 47 ++++++--- docs/cloud-security/code-security/autofix.md | 82 +++++++++++++-- .../code-security/bring-your-own-scanner.md | 38 +++++-- .../code-security/code-rules.md | 2 + .../code-security/container-registries.md | 24 +++++ .../code-security/containment-setup.md | 15 ++- .../code-security/data-handling.md | 21 +++- .../code-security/getting-started.md | 46 +++++++-- .../code-security/incident-response.md | 2 + docs/cloud-security/code-security/index.md | 7 ++ docs/cloud-security/code-security/policy.md | 53 ++++++---- .../code-security/pull-requests.md | 2 + .../cloud-security/code-security/reference.md | 25 +++-- docs/cloud-security/code-security/results.md | 15 +++ .../code-security/troubleshooting.md | 4 +- docs/cloud-security/provider-setup/entra.md | 30 +++++- docs/cloud-security/remediation-sla.md | 2 +- docs/cloud-security/setup-cli.md | 12 ++- docs/email-security/api-reference.md | 3 +- docs/email-security/cli.md | 16 +++ docs/email-security/custom-rules.md | 99 +++++++++---------- docs/email-security/detections.md | 6 +- docs/email-security/getting-started.md | 4 + docs/email-security/messages.md | 12 +++ docs/email-security/policy.md | 21 +++- .../provider-setup/google-workspace.md | 5 +- .../provider-setup/microsoft-365.md | 5 +- docs/email-security/rule-reference.md | 4 - docs/email-security/setup-cli.md | 51 ++++++++-- docs/includes/code-security-cli-version.md | 5 + docs/includes/code-security-cli.md | 25 +++++ snippets/python/cloudsec_findings.py | 16 +++ 35 files changed, 602 insertions(+), 155 deletions(-) create mode 100644 docs/includes/code-security-cli-version.md create mode 100644 docs/includes/code-security-cli.md create mode 100644 snippets/python/cloudsec_findings.py diff --git a/.github/workflows/snippet-tests.yml b/.github/workflows/snippet-tests.yml index c4a7def47..59e251aa5 100644 --- a/.github/workflows/snippet-tests.yml +++ b/.github/workflows/snippet-tests.yml @@ -71,7 +71,7 @@ jobs: # reorganizes modules fails the PR that bumps it, not an unrelated PR. run: | pip install --upgrade pip - pip install 'limacharlie==5.5.1' + pip install 'limacharlie==5.6.2' - name: Byte-compile (do not run) the Python snippets run: python -m py_compile snippets/python/*.py @@ -83,5 +83,6 @@ jobs: from limacharlie.sdk.organization import Organization from limacharlie.sdk.search import Search from limacharlie.sdk.hive import Hive, HiveRecord + from limacharlie.sdk.cloudsec import CloudSec print("SDK import paths used by the documentation snippets all resolve.") PY diff --git a/docs/6-developer-guide/sdks/python-sdk.md b/docs/6-developer-guide/sdks/python-sdk.md index 76804affe..3096ad781 100644 --- a/docs/6-developer-guide/sdks/python-sdk.md +++ b/docs/6-developer-guide/sdks/python-sdk.md @@ -14,9 +14,10 @@ 10. [Hive Operations](#hive-operations) 11. [Search (LCQL)](#search-lcql) 12. [Extensions](#extensions) -13. [Infrastructure as Code](#infrastructure-as-code) -14. [Error Handling](#error-handling) -15. [Complete Examples](#complete-examples) +13. [Cloud, Code and Email Security](#cloud-code-and-email-security) +14. [Infrastructure as Code](#infrastructure-as-code) +15. [Error Handling](#error-handling) +16. [Complete Examples](#complete-examples) ## Overview @@ -41,7 +42,7 @@ The LimaCharlie Python SDK provides a comprehensive interface for interacting wi ### Requirements -- Python 3.9 or higher +- Python 3.10 or higher - pip package manager ### Install via pip @@ -710,6 +711,44 @@ response = ext.request( ) ``` +## Cloud, Code and Email Security + +### Cloud Security + +The stable SDK exposes `CloudSec` through `limacharlie.sdk.cloudsec`. The +organization must be subscribed to Cloud Security; reading findings requires +`cloudsec.get`. This example targets SDK **5.6.2** and follows every page while +keeping its filters unchanged: + +```python +--8<-- "snippets/python/cloudsec_findings.py" +``` + +The wrapper returns response dictionaries rather than typed finding objects. +Connection and policy configuration uses `Hive` (`cloudsec_provider`, +`cloudsec_policy`, `cloudsec_query`, `cloudsec_code_rule`). See +[Cloud Security setup](../../cloud-security/setup-cli.md) for the permission +split and [API reference](../../cloud-security/api-reference.md) for response +fields. + +### Code Security and Email Security availability + +Stable SDK 5.6.2 does **not** contain Code Security's SDK methods or the +`Mailsec` wrapper. Those interfaces are available in the development version +of the [public Python SDK](https://github.com/refractionPOINT/python-limacharlie). +Use a separate environment and pin a tested commit for automation. Follow +[Code Security CLI installation](../../cloud-security/code-security/getting-started.md#cli-installation) +or [Email Security setup](../../email-security/setup-cli.md) before copying +examples. Installing the development SDK does not enable server capabilities +or grant beta access. + +Email Security requires its extension subscription and separates reading +(`mailsec.get`), policy/triage edits (`mailsec.set`), provider actions +(`mailsec.act`) and raw-email access (`mailsec.get.eml` on top of +`mailsec.get`). Provider records have their own `mailsec_provider` permissions. +See [Email Security API reference](../../email-security/api-reference.md) and +[permission setup](../../email-security/setup-cli.md#2-grant-the-permissions). + ## Infrastructure as Code ```python diff --git a/docs/cloud-security/api-reference.md b/docs/cloud-security/api-reference.md index ad2a318b9..a97b853fc 100644 --- a/docs/cloud-security/api-reference.md +++ b/docs/cloud-security/api-reference.md @@ -8,9 +8,11 @@ Authentication is the standard `Authorization: Bearer ` header. !!! info "Permissions & enable gate" Reads — and the read-only preview `POST`s (`query`, `simulate/resources`, `simulate/findings`, `policy/suggest`) — require `cloudsec.get`; every - other write requires `cloudsec.set`. Every route requires the - organization to be subscribed to `ext-cloud-security` — a `403` on any - route means subscribe first. The `oid` is always taken from the + other ordinary write requires `cloudsec.set`. Code Security remediation and + AutoFix require `cloudsec.respond`; see [their route permissions](code-security/reference.md#api-routes). + Every route requires the organization to be subscribed to + `ext-cloud-security`. For a `403`, check both the subscription and the + permission named in the error. The `oid` is always taken from the authorized path. Provider *records* are not `/cloudsec` routes: their CRUD goes through Hive (`cloudsec_provider` hive, gated by `cloudsec_provider.get/set/del`). diff --git a/docs/cloud-security/cli.md b/docs/cloud-security/cli.md index 503d46929..a26e61c11 100644 --- a/docs/cloud-security/cli.md +++ b/docs/cloud-security/cli.md @@ -20,6 +20,8 @@ standard `limacharlie hive` commands — see [Configuration](configuration.md); this group is the query and triage surface. +--8<-- "includes/code-security-cli.md" + For Code Security (repositories, SBOMs, AutoFix, local scans and pushed results), see [Code Security](code-security/results.md#from-the-cli) and [Bring your own scanner](code-security/bring-your-own-scanner.md). @@ -167,7 +169,11 @@ limacharlie cloudsec finding list \ --sort lc_risk --order desc \ --limit 50 # ...then pass the returned next_cursor back: -limacharlie cloudsec finding list --cursor "" --limit 50 +limacharlie cloudsec finding list \ + --severity CRITICAL --severity HIGH \ + --status open -q payment \ + --sort lc_risk --order desc \ + --cursor "" --limit 50 ``` Boolean tri-state flags (`--kev/--no-kev`, `--reachable/--no-reachable`) @@ -181,9 +187,9 @@ applies to `finding list`, `finding facets`, `finding causes`, and that defaults to **ascending** (soonest deadline first), keeping findings with no due date last rather than dropping them. -!!! note "`--sla` needs a CLI newer than 5.6.1" - The SLA selector and the `due_at` sort key ship in the first `limacharlie` - release after 5.6.1. On an older CLI, use the `sla=` and `sort=due_at` +!!! note "SLA filters require CLI 5.6.2 or later" + The SLA selector and the `due_at` sort key are available in `limacharlie` + 5.6.2. On an older CLI, use the `sla=` and `sort=due_at` parameters on the [REST route](api-reference.md#reads) — the server-side feature is live either way. @@ -215,19 +221,36 @@ the returned sample, and `simulate resources` takes a repeatable `--resource-type` to narrow the walked types the way an exclusions rule does. `policy suggest` takes `--limit` (default 20, cap 50). +## Additional development CLI selectors + +The following additions are newer than stable 5.6.2. Use the development CLI +installation above and check each command's `--help`; older development +checkouts may not contain them yet. The corresponding REST selectors are in +the [API reference](api-reference.md). + +The current additions are tracked in the +[public SDK update](https://github.com/refractionPOINT/python-limacharlie/pull/408). +Until that update is merged, installing `master` does not include every new +selector in this table; use the REST route or wait for the updated development +CLI before copying those flags. + +| Command | Additional selectors | +|---|---| +| `cloudsec image list` | Repeatable `--lineage-status` (`verified`, `asserted`, `inferred`, `ambiguous`, `unknown`). Stale lineage counts as unknown. | +| `cloudsec image repo-facets` | `--lineage-facet` adds digest-level lineage counts; these counts are separate from registry placement counts. | +| `cloudsec caasm assets` | Repeatable `--kind`, `--source`, `--encryption`, `--screen-lock`, `--compromised`, `--managed`, plus `--sort urn` or `--sort last_seen`. For a posture dimension, an empty value selects unreported state. | +| `cloudsec export findings`, `cloudsec export inventory` | `--max-rows` bounds a CSV chunk; `--cursor` resumes it. A trailing `# next_cursor=...` comment carries the continuation token when more rows remain. Keep all selectors unchanged when resuming. | +| `cloudsec provider m365-certificate` | Generates and stores an Entra connection key pair and returns only its public certificate. See [certificate setup](provider-setup/entra.md#without-the-web-app). | + +A CSV reader should skip `#` comment lines before treating the file as a table. +Check for the continuation token before considering a bounded export complete. + ## Scripting The SDK class behind the CLI is available directly: ```python -from limacharlie.client import Client -from limacharlie.sdk.organization import Organization -from limacharlie.sdk.cloudsec import CloudSec - -cs = CloudSec(Organization(Client(oid="..."))) -page = cs.list_findings(severity=["CRITICAL"], kev=True, limit=100) -for f in page["findings"]: - print(f["lc_risk"], f["title"], f["resource_urn"]) +--8<-- "snippets/python/cloudsec_findings.py" ``` Each method mirrors one API route and returns the raw response dict; see the diff --git a/docs/cloud-security/code-security/autofix.md b/docs/cloud-security/code-security/autofix.md index 8a5c13f55..a8c5d1f43 100644 --- a/docs/cloud-security/code-security/autofix.md +++ b/docs/cloud-security/code-security/autofix.md @@ -1,11 +1,18 @@ # AutoFix pull requests +--8<-- "includes/code-security-cli-version.md" + For a vulnerable dependency with a published fixed version, Code Security can open the GitHub pull request that upgrades it. You review and merge it like any other pull request. -AutoFix is GitHub-only and supports **npm** (including yarn and pnpm projects), -**pip**, **Go modules** and **Maven**. +The walkthrough below uses GitHub. AutoFix supports **npm** (including yarn and +pnpm projects), **pip**, **Go modules** and **Maven**. GitLab.com and Bitbucket +Cloud workflow support is deployment-dependent: confirm workflow availability +with LimaCharlie, configure the provider's separate write token, then use +`code capabilities` to verify the connection can open fix pull requests. A +connection missing from that workflow response may still support +ordinary scheduled repository scanning. ## Turn it on @@ -77,9 +84,11 @@ stale-lockfile warning and the command to run on the branch before merging: | Lockfile | Command | |---|---| | `package-lock.json` | `npm install --package-lock-only --ignore-scripts` | -| `yarn.lock` | `yarn install --mode update-lockfile` | -| `pnpm-lock.yaml` | `pnpm install --lockfile-only` | -| `go.sum` | `go mod tidy` | +| `npm-shrinkwrap.json` | `npm install --package-lock-only --ignore-scripts` | + +This warning applies to npm's JSON lockfiles. A yarn, pnpm or Go lockfile the +service cannot complete safely is refused before the job runs, rather than +opened with a stale-lockfile warning. AutoFix never runs a package manager, because that would run code from the very dependencies under suspicion. To update `package-lock.json`, it makes one @@ -87,8 +96,9 @@ read-only request to the npm registry for the new version's download URL and integrity hash, and writes those into the lockfile. To forbid that registry request, set `autofix_registry_access: false` in the -policy. npm pull requests then change `package.json` only and carry the -stale-lockfile warning. If any policy selecting a repository sets it to `false`, +policy. Projects using npm JSON lockfiles then change `package.json` only and +carry the stale-lockfile warning. Other lockfile formats can instead be refused +if safe completion needs registry metadata. If any policy selecting a repository sets it to `false`, that wins. Separately, LimaCharlie always confirms the fixed version exists on the public @@ -97,7 +107,8 @@ request. Packages published only to a private registry cannot be fixed automatically. AutoFix also refuses changes it cannot make safely, and says why: transitive -dependencies, Go upgrades across a major version, complex npm version ranges, +dependencies, Go upgrades that require a module-path change for major versions +above v1 (v0-to-v1 is allowed), complex npm version ranges, Maven versions inherited from a parent POM, and pip pins other than `==`, `===`, `~=` or `>=`. @@ -138,3 +149,58 @@ Some requests are refused immediately, with an HTTP error: See [Unknown, partial and refusal reasons](reasons.md#remediation-runs) for every code. + +## AI-proposed fixes + +!!! warning "Not currently available" + AI-proposed fix pull requests are a separate capability from dependency + AutoFix. They are not currently enabled as an available service. The + configuration below describes the opt-in contract for organizations that + LimaCharlie enables in a future preview; saving it does not grant access. + +The `ai_fix_pr` action proposes a change to the single file named by a hosted +static-analysis or infrastructure-as-code finding. It uses **your Anthropic +API key**, sends that file and the finding context to Anthropic, and charges +usage to your Anthropic account. Review [AI data handling](data-handling.md#ai) +before opting in. Dependency upgrades continue to use deterministic AutoFix. + +When this capability is available, it needs the GitHub write grants above, +`cloudsec.respond` for requesting and approving each run, and an `ai_fix` block +on an enabled code-scanning policy that selects the repository: + +```yaml +# Add this block INSIDE the code_scanning object in your existing policy. +ai_fix: + enabled: true + model_secret: hive://secret/code-fix-anthropic-key + job_cap_usd: 2 + jobs_per_day: 10 + checks: [syntax] +``` + +Create the referenced enabled secret first, with your Anthropic API key as the +secret value. The optional `model` selects a supported model; omit it to use the +service default and confirm the available models with LimaCharlie during setup. + +| Field | Contract | +|---|---| +| `enabled` | Required inside the block. `false` denies AI fixes for every repository the policy selects. Absent `ai_fix` leaves AI fixes off unless another selecting policy enables them. | +| `model_secret` | Required when enabled; a `hive://secret/` reference, never an inline API key. | +| `job_cap_usd` | Per-model-call budget, USD 0.10–10; default 2. A job that cannot fit its input and output budget makes no model call. | +| `jobs_per_day` | Per-organization daily job cap, 1–50; default 10. Failed jobs count when they start. | +| `checks` | `syntax` (default) or `none`. The service never accepts a command to execute. `none` skips only the optional syntax check; rescanning and the impact gate remain mandatory. | + +Across selecting policies, an explicit denial wins, caps take the lowest value, +and required checks combine. Conflicting model or secret choices refuse the +job. The default syntax check supports Go, JSON, YAML, Terraform and HCL files; +unsupported file types are refused rather than treated as having passed. + +The model cannot choose a repository, target file, branch, commit or command. +A proposed patch must remove the target finding in a sandboxed rescan, pass the +configured checks, and pass the live-impact gate before a pull request opens. +Missing or partial evidence refuses the job. Each run still needs explicit +approval, and its pull request needs your normal review and merge process. + +To disable this opt-in, set `ai_fix.enabled: false` in a policy selecting the +repository. Cancel any active run separately; changing a policy does not close +pull requests already opened. diff --git a/docs/cloud-security/code-security/bring-your-own-scanner.md b/docs/cloud-security/code-security/bring-your-own-scanner.md index 2ad1359ee..47e852071 100644 --- a/docs/cloud-security/code-security/bring-your-own-scanner.md +++ b/docs/cloud-security/code-security/bring-your-own-scanner.md @@ -1,5 +1,7 @@ # Bring your own scanner +--8<-- "includes/code-security-cli-version.md" + You don't have to rely only on the hosted scan. You can: - **push results from a scanner you already run**, as SARIF or CycloneDX; @@ -85,6 +87,14 @@ days without a push for a new commit. `code scan` runs the LimaCharlie scanner on a checkout. Your code never leaves the machine, only the report does. +The default container requires Docker and access to the scanner image +distribution; anonymous pulls are not currently available. Confirm image access +with LimaCharlie before using it in CI, or provide an authorized scanner image +with `--image` or an installed `scanner-agent` with `--binary`. The CLI does not +install the scanner binary. If you already have another scanner, SARIF or +CycloneDX ingestion above does not require LimaCharlie's scanner image. Hosted +scanning is another option when it is available in your data region. + ```bash # Scan and keep the report, without sending anything. limacharlie cloudsec code scan ~/src/payments -o report.json.gz @@ -98,13 +108,13 @@ limacharlie cloudsec code scan ~/src/payments --repo acme/payments --ingest - `--scanners` defaults to `sca,iac,licenses`. `sast` and `images` can also run locally. Locally, `images` lists the images your Dockerfiles use but does not scan them. -- Local static analysis **never applies your organization's - [code rules](code-rules.md)**. With the CLI's default container image, it runs - the default rules built into that scanner image. Scanner releases that support - code rules have no built-in rules. They run static analysis only when started - with their `--default-rules` flag (LimaCharlie's default set) or `--rules-file`, - and the CLI does not pass either one. So pointing `--image` or `--binary` at one - of those releases gives a report with `sast_no_rules` and no code weaknesses. +- With `sast` in `--scanners`, the CLI supplies LimaCharlie's default static + analysis rules. Use `--org-rules` to read your organization's enabled + [code rules](code-rules.md), or `--rules-file rules.json` for a local rule-set + document (`{"version":1,"records":[...]}`). These two options are mutually + exclusive. `--org-rules` needs authentication and `cloudsec.get`; the local + default and file options do not. A custom scanner image or binary must be + version 0.16.0 or later to accept the rule flags. - A scan must use `--ingest`, `-o`, or both, so the report is never thrown away. - `--repo` is read from the checkout's git remote when possible. Pass it explicitly in CI. @@ -113,6 +123,15 @@ limacharlie cloudsec code scan ~/src/payments --repo acme/payments --ingest rather than skipping secrets quietly. Local findings could not be matched to the hosted scan's secret findings, so use the hosted scan for secrets. +```bash +# Offline static analysis using LimaCharlie's defaults. +limacharlie cloudsec code scan . --scanners sast -o report.json.gz + +# Use the same enabled static-analysis records as a hosted scan of your org. +limacharlie cloudsec code scan . --scanners sca,sast --org-rules \ + --oid "$OID" -o report.json.gz +``` + ### GitHub Actions This workflow scans every push to `main` and pushes the report. The scan runs on @@ -135,7 +154,10 @@ jobs: - uses: actions/checkout@v4 - name: Install the LimaCharlie CLI - run: pipx install limacharlie + # Code Security commands are not in stable 5.6.2. This public SDK + # revision contains the commands and static-analysis rule options. + # Update the pin deliberately after testing your workflow. + run: pipx install 'git+https://github.com/refractionPOINT/python-limacharlie.git@e40d0889ff3271e2c5670fff8358b257b5cc404c' - name: Scan and push env: diff --git a/docs/cloud-security/code-security/code-rules.md b/docs/cloud-security/code-security/code-rules.md index 18dcae2af..e33d88674 100644 --- a/docs/cloud-security/code-security/code-rules.md +++ b/docs/cloud-security/code-security/code-rules.md @@ -1,5 +1,7 @@ # Code rules +--8<-- "includes/code-security-cli-version.md" + Static analysis runs **exactly your organization's enabled code rules** — nothing else. They are records in the `cloudsec_code_rule` Hive, and LimaCharlie's rules are records there too: there is no hidden built-in pack and no separate override diff --git a/docs/cloud-security/code-security/container-registries.md b/docs/cloud-security/code-security/container-registries.md index cfa67f6db..9119df3f7 100644 --- a/docs/cloud-security/code-security/container-registries.md +++ b/docs/cloud-security/code-security/container-registries.md @@ -15,6 +15,30 @@ Registry credentials are used by the short-lived image fetch job. The scan conta For Docker Hub, Quay.io, and GHCR, store the token in a LimaCharlie secret and create one registry credential setting **per repository**. Enter the registry, repository name (for example, `team/app`), username, and the secret reference. The setting cannot contain a literal token. Use a read-only account or token, and grant it access only to repositories that must be scanned. A credential for `team/app` is never used to pull `team/other`. +To manage the same setting as code, create an enabled secret with the registry +token as its value, then save `registry-credential.yaml`: + +```yaml +policy_type: registry_credential +registry_credential: + registry: ghcr + repository: team/app + username: registry-reader + secret_ref: hive://secret/ghcr-team-app +``` + +```bash +limacharlie hive set --hive-name cloudsec_policy --key ghcr-team-app \ + --input-file registry-credential.yaml --enabled --oid "$OID" +``` + +`registry` is `dockerhub`, `quay` or `ghcr`, not a registry URL. Repository +paths are exact, lowercase and contain no tag or digest. Docker Hub and Quay +accept `namespace/image`; GHCR also accepts nested paths. Saving the policy +needs `cloudsec.set` **and read access to the referenced secret**, including +any record ACL. Create the secret before saving the policy; a misspelled or +unreadable reference is refused. + For ECR and ACR, LimaCharlie uses your existing cloud connection. It exchanges that connection for a short-lived registry pull credential; no second long-lived credential is needed. Each pull credential can read only the one repository being scanned: ACR tokens request `repository::pull`, and ECR tokens come from a session whose policy allows reads on that single repository. ECR images are pulled only from the connected AWS account, or from member accounts that AWS Organizations confirms belong to the connected organization. Images in other AWS accounts are reported as not scanned; LimaCharlie does not request credentials for them. Likewise, ACR images are pulled only from registries that LimaCharlie has inventoried through your connected Azure subscriptions. diff --git a/docs/cloud-security/code-security/containment-setup.md b/docs/cloud-security/code-security/containment-setup.md index 46f344beb..7bfbf2048 100644 --- a/docs/cloud-security/code-security/containment-setup.md +++ b/docs/cloud-security/code-security/containment-setup.md @@ -1,5 +1,7 @@ # Configure evidence, lineage and remediation +--8<-- "includes/code-security-cli-version.md" + This page covers the settings behind the evidence chain, image lineage, live pull-request impact, runtime checks and remediation runs. It lists the permissions each one needs, what to grant on each connection, and which @@ -7,9 +9,13 @@ policies control them. For what these features promise, see [What Code Security guarantees](guarantees.md). !!! note "Availability" - These capabilities are enabled region by region. Until yours is on, the + These are conditional API contracts, not a promise that every capability + is available in your organization. Evidence and lineage are introduced + region by region; remediation and AI-proposed fixes are not generally + available. Confirm access with LimaCharlie before setting them up. Until a capability is on, the routes below answer `feature_disabled`, `disabled` or `codesec_disabled`. - Scanning, pull-request checks and the rest of Code Security are unaffected. + Tenant policies cannot enable it. A refusal does not disable ordinary scans + and pull-request checks that are already available to you. ## Permissions @@ -45,7 +51,10 @@ All of these are read-only unless the row says otherwise. | LimaCharlie sensors | A sensor on the host or node | Runtime checks. Without one the answer is `unknown` with `no_sensors`. | GitLab and Bitbucket connections are scanned with their read tokens. Pull-request -checks, fixes and other writes on GitLab and Bitbucket are not enabled yet. +checks, fixes and other writes require the corresponding workflow capability to +be enabled in your data region and a separately configured write token. Read +`code capabilities` after setup; scheduled repository scanning alone does not +establish write capability. ### Webhooks diff --git a/docs/cloud-security/code-security/data-handling.md b/docs/cloud-security/code-security/data-handling.md index 0804b32d2..6334035df 100644 --- a/docs/cloud-security/code-security/data-handling.md +++ b/docs/cloud-security/code-security/data-handling.md @@ -74,9 +74,24 @@ per-declaration detail, still without resource names. See ## AI -AutoFix does not send your code to a language model. It is deterministic. It -raises one dependency to one version and never runs a package manager. No -AI-generated fix feature is available. +Dependency AutoFix is deterministic: it raises a dependency to a fixed version +and does not send code to a language model or run a package manager. + +[AI-proposed fixes](autofix.md#ai-proposed-fixes) are a separate, currently +unavailable capability with explicit tenant opt-in. If LimaCharlie enables that +capability for your organization and you approve a run, the service sends the +finding's one target file (up to 64 KiB), its path and bounded finding context +to Anthropic, using **your** API key. It sends neither the rest of the repository +nor your cloud estate. Anthropic's processing location and retention are +governed by your Anthropic agreement; the ordinary scan's LimaCharlie data-region +guarantee does not describe that external model call. + +LimaCharlie does not retain the model prompt, response, source file or patch in +findings, audit records or operational events. The run retains structured +validation outcomes and model usage. Source and patch working files are deleted +when the job ends. An approved patch that passes validation appears in the +GitHub pull request, where it follows your repository's retention and access +settings. ## Retention diff --git a/docs/cloud-security/code-security/getting-started.md b/docs/cloud-security/code-security/getting-started.md index d671532e2..85c684a0d 100644 --- a/docs/cloud-security/code-security/getting-started.md +++ b/docs/cloud-security/code-security/getting-started.md @@ -16,9 +16,33 @@ nothing until a policy selects repositories. answers `403`. - You have `cloudsec.get` and `cloudsec.set`. Connecting GitHub with the automatic setup below needs a few more permissions, listed in that section. +- Creating or editing the provider record, including enabling it on that write, + uses `cloudsec_provider.set`. Metadata-only changes can instead use + `cloudsec_provider.set.mtd`. These are separate from policy + and finding permissions. Ask your organization administrator for them if + saving or enabling the connection is denied. - For GitHub, someone who is an **owner of the GitHub organization** is available to approve the App. +Your first goal is one successfully scanned repository. Start with a small +repository you know contains a dependency manifest and source files. In the +console's setup checklist, confirm hosted scanning is available in your data +region before granting provider access. If it is unavailable, contact +LimaCharlie; an enabled policy cannot turn on an unavailable server capability. + +### CLI installation + +The console walkthrough needs no terminal. Use this installation only for the +CLI examples on these pages: + +--8<-- "includes/code-security-cli.md" + +Then [configure authentication](../../6-developer-guide/cli-quickstart.md). Run +`limacharlie org list --output yaml` to find your organization ID; pass +`--oid ` on each command or select it in your CLI profile. +Provider organization names, GitHub slugs and cloud project IDs are different +from your LimaCharlie organization UUID. + ## GitHub: let LimaCharlie create the App This is the fastest path. The console creates a GitHub App in your GitHub @@ -37,6 +61,8 @@ to pushes and pull requests. Nobody has to configure a webhook by hand. - **Turn on code scanning with pull-request checks** creates a [starter policy](#the-starter-policy). It is offered, and ticked, only when the organization has no code-scanning policy yet. + For a one-repository pilot, leave it off and + [create a policy](#create-a-policy) with that repository in `include`. 4. Choose **Continue on GitHub**. GitHub shows the App it is about to create. A GitHub organization owner creates it, then installs it on **All repositories**. @@ -160,14 +186,15 @@ Or as code: ```yaml # code-policy.yaml policy_type: code_scanning -enabled: true -repos: - include: ["acme/api-*", "acme/payments"] -scanners: - sca: true - secrets: true - iac: true - licenses: true +code_scanning: + enabled: true + repos: + include: ["acme/api-*", "acme/payments"] + scanners: + sca: true + secrets: true + iac: true + licenses: true ``` ```bash @@ -175,7 +202,8 @@ limacharlie hive set --hive-name cloudsec_policy --key code-scanning \ --input-file code-policy.yaml --enabled ``` -Static analysis is not listed above because it runs unless a policy sets +Save the YAML as `code-policy.yaml`. The Hive record's `--enabled` switch and +the nested `code_scanning.enabled: true` are both required. Static analysis is not listed above because it runs unless a policy sets `sast: false`. Every field is described in [Scan policy](policy.md). ## Check that it worked diff --git a/docs/cloud-security/code-security/incident-response.md b/docs/cloud-security/code-security/incident-response.md index 2006866a1..1783f880b 100644 --- a/docs/cloud-security/code-security/incident-response.md +++ b/docs/cloud-security/code-security/incident-response.md @@ -1,5 +1,7 @@ # Automatic behavior and incident response +--8<-- "includes/code-security-cli-version.md" + This page describes what Code Security does on its own when something goes wrong, what it never does on its own, and what you can do during an incident that involves a remediation. diff --git a/docs/cloud-security/code-security/index.md b/docs/cloud-security/code-security/index.md index 675f7ca78..97426dac4 100644 --- a/docs/cloud-security/code-security/index.md +++ b/docs/cloud-security/code-security/index.md @@ -1,5 +1,7 @@ # Code Security +--8<-- "includes/code-security-cli-version.md" + Code Security scans the source repositories behind your cloud estate and puts what it finds into the same risk-ranked worklist as your cloud findings. You triage a leaked credential or a vulnerable dependency the same way you triage a @@ -60,6 +62,11 @@ keep it. the GitHub App, and each write uses a token limited to what that one action needs. +These guarantees describe ordinary scans and deterministic dependency AutoFix. +The separate, currently unavailable [AI-proposed fix capability](autofix.md#ai-proposed-fixes) +has an additional opt-in for sending one target file to your model provider; +see [AI data handling](data-handling.md#ai). + ## Where to find it In the console, open **Cloud Security → Code security**. It has four tabs: diff --git a/docs/cloud-security/code-security/policy.md b/docs/cloud-security/code-security/policy.md index 56074e235..a68a721e5 100644 --- a/docs/cloud-security/code-security/policy.md +++ b/docs/cloud-security/code-security/policy.md @@ -1,5 +1,7 @@ # Scan policy +--8<-- "includes/code-security-cli-version.md" + A `code_scanning` policy decides which repositories are scanned, which engines run, how often, and what happens on pull requests. With no enabled policy, nothing is scanned. @@ -11,25 +13,26 @@ store it as a record in the `cloudsec_policy` hive. ```yaml policy_type: code_scanning -enabled: true -repos: - include: ["acme/api-*", "acme/payments"] - exclude: ["acme/api-archive"] -scanners: - sca: true - secrets: true - secrets_history: true - iac: true - images: true - licenses: true - # sast runs unless set to false -schedule: daily -severity_floor: "" -image_sources: ["dockerfile", "workloads"] -pr_checks: true -pr_comments: false -gating: - fail_on: HIGH +code_scanning: + enabled: true + repos: + include: ["acme/api-*", "acme/payments"] + exclude: ["acme/api-archive"] + scanners: + sca: true + secrets: true + secrets_history: true + iac: true + images: true + licenses: true + # sast runs unless set to false + schedule: daily + severity_floor: "" + image_sources: ["dockerfile", "workloads"] + pr_checks: true + pr_comments: false + gating: + fail_on: HIGH ``` ```bash @@ -37,20 +40,30 @@ limacharlie hive set --hive-name cloudsec_policy --key code-scanning \ --input-file code-policy.yaml --enabled ``` +Save the YAML above as `code-policy.yaml`. Both enable switches matter: the +Hive record must be enabled (`--enabled`), and its nested +`code_scanning.enabled` must be `true`. Put `repos`, `scanners` and every field +below **inside `code_scanning`**, not beside `policy_type`. A flat record is +refused because it has no code-scanning body. + ## Fields +These fields belong to the nested `code_scanning` object. + | Field | Meaning | |---|---| | `enabled` | **Required.** `false` keeps the policy but scans nothing. | | `repos.include` | Repositories to scan, as globs matched case-insensitively against `owner/name` and the bare name. **Empty means every repository the connections can see.** | | `repos.exclude` | Repositories to skip. Always wins over `include`. | | `scanners` | Which engines run. See [Engines](#engines). | -| `schedule` | `daily` (the default), `weekly`, or `manual` (only when you ask for a rescan). | +| `schedule` | `daily` (the default), `weekly`, or `manual` (no scheduled scan; an explicit rescan, provider sync or push webhook can still trigger one). | | `severity_floor` | Drop findings below this severity. See [Severity floor](#severity-floor). | | `sast_ruleset` | **Deprecated and ignored.** Old values (`default`, `gitlab`, `custom:`) are still accepted so existing records save, but static analysis always runs the organization's enabled [code rules](code-rules.md). Leave it out of new records. | | `image_sources` | Where the image engine finds images. See [Container images](#container-images). | | `pr_checks`, `pr_comments`, `gating.fail_on` | Pull-request checks on GitHub. `fail_on` is `CRITICAL`, `HIGH`, `MEDIUM`, `LOW` or `NONE` (the default). See [Pull-request checks](pull-requests.md#turn-on-pull-request-checks). | +| `pr_live_context` | Live-impact disclosure on pull-request checks: `off` (default), `risk_summary` or `resource_details`. Least disclosure wins across policies. Requires the impact capability to be available. See [Pull-request disclosure](containment-setup.md#pull-request-disclosure). | | `autofix_registry_access` | Whether AutoFix may look up package registry metadata to update lockfiles. Default `true`. See [AutoFix](autofix.md#lockfiles). | +| `ai_fix` | Reserved opt-in configuration for [AI-proposed fixes](autofix.md#ai-proposed-fixes). Currently unavailable. Saving this block does not enable the server capability. | Globs support `*`, `?`, `[…]`, `{a,b}` and `**`. `*` does not cross a `/`, so `acme/*` does not select a GitLab subgroup project such as `acme/platform/api`. diff --git a/docs/cloud-security/code-security/pull-requests.md b/docs/cloud-security/code-security/pull-requests.md index cf8d66311..92d196295 100644 --- a/docs/cloud-security/code-security/pull-requests.md +++ b/docs/cloud-security/code-security/pull-requests.md @@ -1,5 +1,7 @@ # Pull-request checks and push rescans +--8<-- "includes/code-security-cli-version.md" + A scheduled scan tells you what a repository contains. On GitHub, Code Security can also: diff --git a/docs/cloud-security/code-security/reference.md b/docs/cloud-security/code-security/reference.md index 759cd3355..fd80edf09 100644 --- a/docs/cloud-security/code-security/reference.md +++ b/docs/cloud-security/code-security/reference.md @@ -1,5 +1,7 @@ # Code Security reference +--8<-- "includes/code-security-cli-version.md" + ## Supported languages and ecosystems ### Dependencies (SCA) @@ -160,16 +162,25 @@ remediation requests and decisions need `cloudsec.respond`, a runtime check |---|---|---| | `GET /code/repos` | `code repos` | Repositories with scan status and open-finding counts. Params: `q`, `has_findings`, `provider`, `cursor`, `limit`. | | `GET /code/status` | `code status` | Run status per connection. | -| `GET /code/capabilities` | `code capabilities` | What each GitHub connection can do, and its webhook status. Optional `repo`. | +| `GET /code/capabilities` | `code capabilities` | What enabled source-control workflow connections can do, and their webhook status. Optional `repo`. | | `GET /code/fixes` | `code fixes` | Open dependency findings grouped by the upgrade that fixes them. | | `GET /code/sbom` | `code sbom` | A short-lived download link for one repository's SBOM. Params: `repo` (required, `/` as `/code/repos` returns it), `provider`. | -| `GET /code/images`, `GET /code/images/{digest}` | | Container images and one image's detail. | -| `GET /code/image-repos`, `GET /code/image-repos/facets` | | Image repositories and their filter counts. | +| `GET /code/images`, `GET /code/images/{digest}` | `image list`, `image get` | Container images and one image's detail. | +| `GET /code/image-repos`, `GET /code/image-repos/facets` | `image repos`, `image repo-facets` | Image repositories and their filter counts. | | `POST /code/scan` | `code rescan` | Rescan one repository. Body: `{repo, ref?, provider?}`. | | `POST /code/autofix` | `code autofix` | Open an AutoFix pull request as a remediation run. Needs `cloudsec.respond`. Body: `{finding_id, repo?}`. | | `POST /code/ingest` | `code ingest` | Push SARIF, CycloneDX or a scanner report. | -| `POST /code/pr_check` | | Check a pull request. Used by the webhook rules. | -| `POST /code/webhook` | | Point a GitHub App's webhook at LimaCharlie. See [the webhook API](pull-requests.md#the-webhook-api). | +| `POST /code/pr_check` | `code pr-check` | Check a pull request. Used by the webhook rules. | +| `POST /code/webhook` | `code webhook` | Point a GitHub App's webhook at LimaCharlie. See [the webhook API](pull-requests.md#the-webhook-api). | + +Image reads accept repeatable `lineage_status` values: `verified`, `asserted`, +`inferred`, `ambiguous`, `unknown`. Filtering is server-side; a stale lineage +decision counts as `unknown` immediately. Image-repository facets can request +`lineage_facet=true` for digest-level counts under `lineage_statuses`; repository +placement filters do not narrow those lineage counts. An older server that +cannot apply the filter refuses it instead of returning an unfiltered page. +See [image lineage](containment-setup.md#image-lineage) for what each status +proves. Findings are read with the standard [findings routes](../api-reference.md), filtered by `repo`. @@ -195,6 +206,8 @@ they return. - **Scanning images from container registries.** `image_sources: ["registries"]` is accepted but does nothing yet. -- **Pull-request checks, push rescans and AutoFix on GitLab and Bitbucket.** +- **GitLab and Bitbucket workflows without the corresponding server capability.** + Support depends on rollout in your data region. Read `code capabilities`; + scheduled repository scans do not imply webhook, check or AutoFix support. - **Scanning self-managed GitLab instances.** They can be connected for inventory. - **Bitbucket Data Center** (self-hosted). diff --git a/docs/cloud-security/code-security/results.md b/docs/cloud-security/code-security/results.md index b6ee9533f..460844d4a 100644 --- a/docs/cloud-security/code-security/results.md +++ b/docs/cloud-security/code-security/results.md @@ -1,5 +1,7 @@ # Working with results +--8<-- "includes/code-security-cli-version.md" + Code findings are ordinary [Cloud Security findings](../findings.md). They share the worklist, the triage actions (mitigated, accepted, false positive), owners, tickets, [remediation SLAs](../remediation-sla.md) and the `cloud_finding.*` @@ -58,6 +60,19 @@ installation, the drawer says so and links to the installation page. Select an image to open its findings in Risks. **Registries** groups images by image repository. +From the development CLI: + +```bash +limacharlie cloudsec image repos +limacharlie cloudsec image repo-facets +limacharlie cloudsec image list --running --findings with +limacharlie cloudsec image get "sha256:" +``` + +Read an image's lineage status alongside its findings. `verified`, `asserted` +and `inferred` describe different strengths of source attribution; they do not +say the image is safe. See [Image lineage](containment-setup.md#image-lineage). + ### Risks Code findings appear in the main worklist on **Risks**. Use the **Repository** diff --git a/docs/cloud-security/code-security/troubleshooting.md b/docs/cloud-security/code-security/troubleshooting.md index 47216c777..c61adc070 100644 --- a/docs/cloud-security/code-security/troubleshooting.md +++ b/docs/cloud-security/code-security/troubleshooting.md @@ -1,5 +1,7 @@ # Troubleshooting Code Security +--8<-- "includes/code-security-cli-version.md" + For evidence-chain, lineage, runtime-check and remediation reason codes, see [Unknown, partial and refusal reasons](reasons.md). @@ -71,7 +73,7 @@ if it is shown. It names what is not set up and links to the fix. From the CLI, | Problem | What to check | |---|---| -| `No such command` for `cloudsec code` | Upgrade the `limacharlie` CLI. | +| `No such command` for `cloudsec code` | Stable 5.6.2 does not include this group. Use the [development CLI installation](getting-started.md#cli-installation), or the console / REST routes. | | The CLI cannot identify the repository | Pass `--repo /`. | | Docker is not found | Install and start Docker, or use `--binary`, or push results from your own scanner with `code ingest`. | | A pushed repository is not recorded | It must match an enabled code-scanning policy and fit within the repository limits. | diff --git a/docs/cloud-security/provider-setup/entra.md b/docs/cloud-security/provider-setup/entra.md index c327fd53c..2f2a479a8 100644 --- a/docs/cloud-security/provider-setup/entra.md +++ b/docs/cloud-security/provider-setup/entra.md @@ -232,14 +232,36 @@ upload the new one. ### Without the web app -The certificate comes from an API route: +The stable CLI's API command generates the certificate without requiring you to +manage a JWT yourself: ```bash -curl -X POST -H "Authorization: Bearer $JWT" -H "Content-Type: application/json" \ - "https://api.limacharlie.io/v1/cloudsec/$OID/providers/m365/certificate" \ - -d '{"connection": "entra-prod"}' +limacharlie api "/v1/cloudsec/$OID/providers/m365/certificate" \ + --method POST --json --raw-field connection=entra-prod --output json \ + > certificate-response.json + +# Only the public certificate is returned. Upload this .cer to Entra. +jq -r .certificate certificate-response.json | base64 --decode > entra-prod.cer +``` + +Development CLI builds with `cloudsec provider m365-certificate` offer the same +operation and write the public certificate directly: + +```bash +limacharlie cloudsec provider m365-certificate entra-prod \ + --out entra-prod.cer --oid "$OID" --output yaml ``` +Stable 5.6.2 does not include this dedicated command; use `api` above or check +the development command's `--help` before running it. The dedicated command is +in the [public SDK update](https://github.com/refractionPOINT/python-limacharlie/pull/408); +use `api` while that update is pending. Both forms require +`cloudsec.set` and `secret.set`. A repeat returns the existing certificate. +`--replace` (API `replace: true`) immediately replaces the stored private key; +an existing connection may stop authenticating until you upload the new public +certificate to its Entra app registration. Use the rotation process above for +ordinary renewal. + `connection` is the name of the provider record you are about to create. The optional `client_id` records the app registration's ID, and `"replace": true` replaces an existing certificate. The response carries `credentials` (the diff --git a/docs/cloud-security/remediation-sla.md b/docs/cloud-security/remediation-sla.md index 40890be4c..d05434cc6 100644 --- a/docs/cloud-security/remediation-sla.md +++ b/docs/cloud-security/remediation-sla.md @@ -259,7 +259,7 @@ usual worklist fields. deadline column — and it places findings with **no** due date last rather than dropping them from the page. - `--sla` and `--sort due_at` require a `limacharlie` CLI newer than 5.6.1. On + `--sla` and `--sort due_at` require `limacharlie` 5.6.2 or later. On an older CLI, pass `sla=` and `sort=due_at` on the [REST route](api-reference.md#reads) directly. diff --git a/docs/cloud-security/setup-cli.md b/docs/cloud-security/setup-cli.md index cf874a3ca..fee0b33b2 100644 --- a/docs/cloud-security/setup-cli.md +++ b/docs/cloud-security/setup-cli.md @@ -2,7 +2,7 @@ Prefer the web app? Start with the [console walkthrough](getting-started.md). -Before running commands, [install and configure the CLI](../6-developer-guide/cli.md) and select your organization. `$OID` below means your LimaCharlie organization ID. +Before running commands, [install and configure the CLI](../6-developer-guide/cli-quickstart.md) and select your organization. `$OID` below means your LimaCharlie organization UUID, not its display name. Use `limacharlie org list --output yaml` to find it and set `OID=""` for these examples. This reference takes an organization from zero to a populated Cloud Security dashboard: enable the product, connect a provider, run the first sweep, and @@ -64,6 +64,16 @@ scope (which account/tenant/org to enumerate) and a read-only credential. The [Connecting Providers](providers.md) page has the full per-provider setup — the steps below use Google Cloud as the worked example. +Creating a connection, including `--enabled` on the same data write, needs +`cloudsec_provider.set`. A metadata-only enable/disable can instead use +`cloudsec_provider.set.mtd`, with metadata read access to preserve other fields. +Saving and enabling its credential secret in one write needs `secret.set`. +Reading connection data uses +`cloudsec_provider.get`, while reading findings uses `cloudsec.get`. +Credential tests and policy edits require `cloudsec.set`. These are separate +grants, so permission to triage a finding does not grant permission to connect +a different provider account. + ### In the console Open **Cloud Security → Settings → Providers** and click **+ Add provider**. diff --git a/docs/email-security/api-reference.md b/docs/email-security/api-reference.md index 97cdd4809..96888e9f9 100644 --- a/docs/email-security/api-reference.md +++ b/docs/email-security/api-reference.md @@ -9,7 +9,8 @@ standard `Authorization: Bearer ` header. !!! info "Permissions & enable gate" Every route requires the organization to be subscribed to - `ext-email-security` — a `403` on any route means subscribe first. The `oid` + `ext-email-security`. For a `403`, check both the subscription and the + permission named in the error. The `oid` is always taken from the authorized path. Reads and the read-only `POST`s (`analyze`, `rules/validate`, diff --git a/docs/email-security/cli.md b/docs/email-security/cli.md index a06c51bd4..a771ea0e8 100644 --- a/docs/email-security/cli.md +++ b/docs/email-security/cli.md @@ -70,10 +70,14 @@ typing a justification to look at the queue. # Coverage limacharlie mailsec coverage --window-days 30 +# Explicit UTC window instead of window-days (development builds with these flags). +limacharlie mailsec coverage --since "2026-09-01T00:00:00Z" --until "2026-09-02T00:00:00Z" + # The triage queue limacharlie mailsec message list --verdict suspicious --verdict malicious limacharlie mailsec message list --mailbox cfo@corp.example --since 2026-08-01 limacharlie mailsec message list --user-reported # a human flagged these +limacharlie mailsec message list --lane backfill # historical analysis, not live actions limacharlie mailsec message list --link-domain evil.example # IOC pivot limacharlie mailsec message list --attachment-sha256 # IOC pivot limacharlie mailsec message get @@ -118,6 +122,9 @@ limacharlie mailsec rule backtest --file rule.json --since 2026-08-01 limacharlie mailsec analyze --file suspect.eml --org-domain corp.example limacharlie mailsec connection test gws-exp limacharlie mailsec onboarding --provider gworkspace +limacharlie mailsec onboarding --provider gworkspace \ + --project-id "$GCP_PROJECT" --sa-email "$SERVICE_ACCOUNT_EMAIL" \ + --topic mailsec-gmail-push --subscription mailsec-gmail-push-sub # Delete everything Email Security holds for this org — previews without --confirm limacharlie mailsec tenant purge @@ -125,6 +132,15 @@ limacharlie mailsec tenant purge `--window-days` accepts 1-35 (the platform's maximum message retention) and cannot be combined with an explicit `--since`/`--until`. Out-of-range values for `--limit`, `--min-score` and `--min-members` are refused with an error naming the flag rather than silently clamped or ignored. +The `--lane`, explicit coverage-window and personalized-onboarding flags are +development additions. Check the command's `--help`; an older development +checkout may lack them. They are tracked in the +[public SDK update](https://github.com/refractionPOINT/python-limacharlie/pull/408); +until it is merged, `master` does not include every new flag. Use the equivalent query parameters in the +[API reference](api-reference.md#reads) with `limacharlie api` until you update. +`--lane` cannot be combined with `--mailbox`, `--sender-email` or `--campaign-id`; +it filters where a message was judged, not its threat verdict. + ## Things worth knowing before you script this ### Campaign actions preview by default diff --git a/docs/email-security/custom-rules.md b/docs/email-security/custom-rules.md index f0cdaf8b5..9d9be9653 100644 --- a/docs/email-security/custom-rules.md +++ b/docs/email-security/custom-rules.md @@ -9,12 +9,24 @@ inspect the full YAML/JSON, edit, enable, disable or delete any rule. Reading ta ## Default rules and ownership -The first subscription installs LimaCharlie's defaults as ordinary enabled records. -After installation they are yours. There is no hidden pack, reserved record-name +The first subscription installs LimaCharlie's defaults as ordinary enabled records +tagged `limacharlie`. There is no hidden pack or reserved record-name prefix, global managed-detection switch, or per-rule policy override. The record key is the rule ID. Default keys such as `ms-link-credentials-in-url` are ordinary keys with exactly the same permissions and behavior as names you choose. +New rule-pack releases update **vendor-tagged records** automatically during the +daily extension update: new defaults are added, changed vendor bodies are +replaced, and retired vendor rules are removed. Your enabled/disabled choices, +expiry and extra tags are preserved. Removing a default is not a durable way to +turn it off: a missing default is recreated at the next pack release. **Disable +it instead.** + +To maintain your own version, copy a default to a new key without the +`limacharlie` tag, then disable its vendor original. Alternatively, remove that +tag from the existing record before customizing it. Records without the vendor +tag are not replaced by pack updates. Keep a copy in version control. + Only enabled records run. With no enabled `pre_verdict` rules, messages remain `unknown`. When scoring rules run but none matches, the verdict can be `benign`. Rule changes normally apply on the next rule reload, within ten minutes. If a @@ -22,7 +34,7 @@ reload fails, the collector keeps the last successfully loaded set and reports the failure. Existing verdicts are not rewritten by a configuration edit. The subscription's one-time installation marker survives unsubscribe/resubscribe. -Deleted rules never return on a background refresh or a later subscription callback. +Resubscribing alone does not recreate deleted rules; a subsequent pack update can. If the initial installation was interrupted or partially failed, use **Restore defaults** to complete it. @@ -43,6 +55,17 @@ The extension performs writes with its own identity. `ext.request` authorizes calling the action; the console additionally requires `mailsec.set`. Records outside the extension's segment cannot be overwritten and are reported as failed. +To apply the current pack update immediately, preserving vendor rules' enabled +states and leaving customer-owned records alone: + +```bash +limacharlie extension request --name ext-email-security \ + --action restore_default_rules --data '{"upgrade": true}' --oid "$OID" +``` + +`upgrade` and `overwrite` cannot be combined: upgrade keeps your vendor-rule +enable choices, while overwrite explicitly resets existing defaults. + ## Infrastructure as code The UI, Hive API and CLI edit the same records. Use `limacharlie hive list`, @@ -462,50 +485,26 @@ fields that distinguish them: does **not** undo the action it took — write the compensating rule if you want one. -## Maintaining the default rule sources - -For contributors with access to the product repositories, `mail-rules` contains -the source pack and its sample harness. The shipped default sources live in -`go-mailsec/signals/rules/`. `ext-email-security` converts them into ordinary -Hive records during initial installation or explicit restoration; -`legion_mailsec` evaluates the organization's enabled records. Updating the -source pack does not replace an existing organization's rules. - -`go-cloudsec` owns the separate configuration-posture rules described in -[Mail Posture Rules](../cloud-security/mail-posture-rules.md). - -Default source files contain a top-level `rules` list. Each rule has a stable `id`, -`name`, `phase: pre_verdict`, `class`, `weight`, `confidence`, `tags`, -`attack_types`, `fp_notes`, and `detect`. Unlike a graymail Hive record, -a source graymail entry uses `weight: 0`. Do not copy a source file directly -into `dr-mail`: remove the list wrapper and body ID, choose the record key, -omit graymail weight, and replace any wildcard paths with supported conditions. - -The contribution workflow is: - -1. Change the YAML under `mail-rules/rules/`. Preserve rule IDs; retire and add a - new ID when changing the meaning of a rule. Update false-positive notes. -2. Add positive and near-miss RFC 5322 samples under - `samples//positive/` and `samples//negative/`. Use reserved - domains such as `.example` and `.invalid` for fixture addresses and URLs. -3. Supply runtime-only enrichment facts in `.enrich.json` sidecars. - Authentication results, headers, link mismatches, and other parse-derived - evidence must come from the EML bytes. The harness runs the real parser and - pure enrichers before applying sidecars. -4. Run the harness from its module directory: - - ```bash - cd mail-rules/harness - go test ./... - ``` - -5. Sync approved changes into `go-mailsec/signals/rules/`, update its default-pack - version, and run the library's rule and corpus tests. Check the extension's - library pin before expecting an installation or restore to use the new defaults. - Live verdicts identify the effective rules and policy by their configuration - fingerprint; existing Hive records change only through an explicit edit or restore. - -The harness checks compilation, sample coverage, positive and negative behavior, -fixture hygiene, and the benign-corpus gate. Its current benign-corpus gate -requires zero flagged messages. A change needs both a sample that should match -and a plausible benign sample that should not. +## Maintaining your rules + +Your own untagged `dr-mail` records stay under your control. For vendor defaults, +follow the [ownership guidance](#default-rules-and-ownership) above so a pack +update does not replace your edits. [Restore defaults](#restore-defaults) +explicitly when you want to return to the current LimaCharlie pack. + +For a rule you maintain: + +1. Keep the single-record JSON or YAML body in your own version control. +2. Validate it with `mailsec rule validate` before saving it. +3. Use `mailsec rule backtest` to test the unsaved candidate against retained + mail. Review the context limitations and skipped-message counts above. + `mailsec analyze` evaluates the currently enabled organization rules, so it + cannot test an unsaved candidate; use it to inspect sample parsing and the + current pack's results. +4. Save the candidate in a pilot organization with `limacharlie hive set + --hive-name dr-mail`, using a stable record key and `--enabled`. Analyze + positive and near-miss samples there before promoting it to wider coverage + or permitting automated responses. + +Keep [mail posture rules](../cloud-security/mail-posture-rules.md) separate: +they evaluate provider configuration, while these rules evaluate messages. diff --git a/docs/email-security/detections.md b/docs/email-security/detections.md index 6809fda3b..cad015da2 100644 --- a/docs/email-security/detections.md +++ b/docs/email-security/detections.md @@ -264,7 +264,11 @@ makes a history rule an amplifier of *other* evidence and never of itself. ## The default rules -LimaCharlie's default rules are installed once into `dr-mail` when you subscribe. +LimaCharlie's default rules are installed into `dr-mail` when you subscribe. +Vendor-tagged defaults receive later pack updates, preserving enabled/disabled +choices. Disable an unwanted default; deleting it can let the next pack release +recreate it. Copy or untag a rule before maintaining your own version. See +[default rule ownership](custom-rules.md#default-rules-and-ownership). **Email Security → Rules** is the authoritative catalog for your organization: it shows the exact current conditions, weight, confidence, phase, tags and false-positive notes. Every default is editable, disableable and deletable. diff --git a/docs/email-security/getting-started.md b/docs/email-security/getting-started.md index d1c039900..a18558022 100644 --- a/docs/email-security/getting-started.md +++ b/docs/email-security/getting-started.md @@ -33,6 +33,10 @@ A **credential** is the key the product uses to access your mail provider. A pauses; data is removed 30 days later unless the organization moves off the free tier. See [trial details](policy.md#plans-the-free-trial-and-the-mailbox-cap). + During private beta, limits may be reported before enforcement is enabled. + Check the Overview trial/coverage information (or `coverage.entitlement` + from the API) for the standing actually in force in your organization. + ## 1. Enable Email Security In your LimaCharlie organization, open **Extensions**, find **Email Security**, diff --git a/docs/email-security/messages.md b/docs/email-security/messages.md index 5a8ea08d8..a840e7838 100644 --- a/docs/email-security/messages.md +++ b/docs/email-security/messages.md @@ -46,6 +46,18 @@ limacharlie mailsec message list --verdict suspicious --verdict malicious \ --mailbox cfo@corp.example --since "$(date -d '7 days ago' +%s)" --oid $OID ``` +To inspect historical analysis separately, a development CLI with `--lane` +supports `mailsec message list --lane backfill`. For an older build, the stable +CLI's API command can send the same filter: + +```bash +limacharlie api "/v1/mailsec/$OID/messages" \ + --raw-field lane=backfill --field limit=10 --output yaml +``` + +Historical messages are scored but do not trigger live-mail telemetry or +automatic responses; an empty action history on one is expected. + !!! warning "Tri-state booleans: absent is not `false`" Omitting `user_reported` means the dimension is *unconstrained*. Setting it to `false` selects mail **nobody reported**, which is a different and much diff --git a/docs/email-security/policy.md b/docs/email-security/policy.md index 486a1ea53..9495fcac8 100644 --- a/docs/email-security/policy.md +++ b/docs/email-security/policy.md @@ -12,6 +12,12 @@ fleet-wide policy are a script, not a UI workflow. | `mailsec_policy` | many, discriminated by `policy_type` | automations, exclusions, VIPs, thresholds, banners, retention, reporter replies, hunt defaults, clustering | | `dr-mail` | one per rule | all mail rules, including installed defaults — see [Custom Rules](custom-rules.md) | + + +Mail rules are ordinary `dr-mail` records, not a `managed_rules` policy type. +See [default rule ownership and updates](custom-rules.md#default-rules-and-ownership) +before customizing the installed pack. + ## How `mailsec_policy` records work Every record carries a `policy_type` discriminator. There may be **many records @@ -34,7 +40,7 @@ How each type composes: | `vips` | Union, deduplicated and sorted | | `thresholds` | Last writer wins per field, with the ordering invariant re-checked afterwards | | `banners`, `reporter_reply`, `hunt_defaults`, `clustering` | Last writer wins per field | -| `retention` | **Maximum** wins — see [Retention](#retention) | +| `retention` | **Minimum** wins — the shortest horizon for each field; see [Retention](#retention) | ### Unknown fields are refused @@ -549,7 +555,8 @@ re-sent for the new date. ## Plans, the free trial, and the mailbox cap -Email Security is available to every organization. What differs between a +Email Security is in private beta and must be available to your organization +before you subscribe. For an enabled organization, what differs between a **trial** organization and a **paid** one is how long it runs and how many mailboxes it protects. @@ -559,10 +566,16 @@ Security and Cloud Security at once gets one answer about what it is paying for. | | Trial | Paid | |---|---|---| -| Duration | **14 days** from the day Email Security was enabled | No limit | -| Protected mailboxes | **25** | No limit | +| Duration | **14 days** from the day Email Security was enabled | No trial duration limit | +| Protected mailboxes | **25** | No plan-imposed mailbox cap | | Everything else — detections, remediation, retention, API, telemetry | Identical | Identical | +These are the trial terms. During beta, a deployment can report limits before +enforcing them. Read `coverage.entitlement` for your actual standing and +enforcement; a reported limit alone does not prove ingestion has paused. Contact +LimaCharlie to confirm trial or scheduled-deletion enforcement in your data +region. Policy records and a development CLI cannot enable server enforcement. + ### The 14-day clock The clock starts the day the organization first subscribes to diff --git a/docs/email-security/provider-setup/google-workspace.md b/docs/email-security/provider-setup/google-workspace.md index 9365d2378..f55cda2bd 100644 --- a/docs/email-security/provider-setup/google-workspace.md +++ b/docs/email-security/provider-setup/google-workspace.md @@ -377,12 +377,13 @@ ingest: backfill_days: 14 features: outbound_observation: true - reports_mailbox: phishing@corp.example pubsub_topic: projects//topics/mailsec-gmail-push pubsub_subscription: projects//subscriptions/mailsec-gmail-push-sub ``` -Replace `pilot@corp.example` with your pilot mailbox addresses. Omitting `scope` +Replace `pilot@corp.example` with your pilot mailbox addresses. If you later +configure `features.reports_mailbox`, use an existing mailbox and include it +in this scope too; otherwise user reports cannot arrive. Omitting `scope` or leaving its include lists empty covers **every discovered mailbox**, subject to exclusions and any domain filter. `include_addresses` and `exclude_addresses` entries must contain `@`; `domains` entries must be bare domains containing a dot, diff --git a/docs/email-security/provider-setup/microsoft-365.md b/docs/email-security/provider-setup/microsoft-365.md index d5c5bc901..d69948bb8 100644 --- a/docs/email-security/provider-setup/microsoft-365.md +++ b/docs/email-security/provider-setup/microsoft-365.md @@ -165,10 +165,11 @@ ingest: backfill_days: 14 features: outbound_observation: true - reports_mailbox: phishing@corp.example ``` -Replace `pilot@corp.example` with your pilot mailbox addresses. Omitting `scope` +Replace `pilot@corp.example` with your pilot mailbox addresses. If you later +configure `features.reports_mailbox`, use an existing mailbox and include it +in this scope too; otherwise user reports cannot arrive. Omitting `scope` or leaving its include lists empty covers **every discovered mailbox**, subject to exclusions and any domain filter. `include_addresses` and `exclude_addresses` entries must contain `@`; `domains` entries must be bare domains containing a dot, diff --git a/docs/email-security/rule-reference.md b/docs/email-security/rule-reference.md index f90059bbc..df05ba3f4 100644 --- a/docs/email-security/rule-reference.md +++ b/docs/email-security/rule-reference.md @@ -139,10 +139,6 @@ Timestamps are RFC 3339 strings. `direction` is `inbound`, `outbound`, or only after scoring. Recursive attachment children and attached messages remain subject to parser and analysis depth limits. - - ### MDM | Field | Type | Presence | diff --git a/docs/email-security/setup-cli.md b/docs/email-security/setup-cli.md index cfb6adb19..3a4d6de34 100644 --- a/docs/email-security/setup-cli.md +++ b/docs/email-security/setup-cli.md @@ -4,7 +4,7 @@ Prefer the web app? Start with the [console walkthrough](getting-started.md). -Install the beta CLI from `master` as shown above, then [configure authentication](../6-developer-guide/cli.md) and select your organization. `$OID` below means your LimaCharlie organization ID. +Install the beta CLI from `master` as shown above, then [configure authentication](../6-developer-guide/cli-quickstart.md) and select your organization. `$OID` below means your LimaCharlie organization UUID, not its display name. Use `limacharlie org list --output yaml` to find it and set `OID=""` for these examples. This reference takes an organization from zero to a populated Email Security queue: enable the product, connect a mail tenant, verify the connection, and read the @@ -28,8 +28,10 @@ Confirm it: limacharlie extension list --oid $OID ``` -Subscribing also seeds the recommended policy records — all in `alert_only` -mode, so nothing moves mail until you say so. See [Policy Reference](policy.md). +Subscribing installs the default detection rules in `dr-mail`. It does not +create automation policy records. With no automation policy, automatic actions +are off; a new automation rule defaults to `alert_only`, so it records intent +without moving mail. See [Policy Reference](policy.md). !!! info "Free trial: 14 days, 25 mailboxes" An organization on the LimaCharlie free tier gets Email Security in full for @@ -45,6 +47,12 @@ mode, so nothing moves mail until you say so. See [Policy Reference](policy.md). read the countdown from, are in [Plans, the free trial, and the mailbox cap](policy.md#plans-the-free-trial-and-the-mailbox-cap). + During private beta, trial limits may be reported before enforcement is + enabled. Check `mailsec coverage` and its `entitlement` block for your + organization's actual standing and enforcement. Contact LimaCharlie if the + reported state and collection behavior disagree; saving a connection alone + does not establish trial eligibility. + ## 2. Grant the permissions Email Security ships four permissions. A user or API key that will triage mail @@ -53,8 +61,22 @@ analyst needs only `mailsec.get`. `mailsec.get.eml` is an escalation on top of `mailsec.get` and should be granted deliberately — see [Overview → Permissions](index.md#permissions). -Managing the connection itself additionally needs the Hive permissions for -`mailsec_provider` and `secret`. +For setup, ask your administrator for the permissions that match your tasks: + +| Task | Permissions | +|---|---| +| Subscribe | `billing.ctrl`, `user.ctrl` | +| Read, create or edit connections (including `--enabled` on a data write) | `mailsec_provider.get`, `mailsec_provider.set` | +| Enable or disable an existing connection without editing its data | Read access to its metadata (`mailsec_provider.get.mtd` or `mailsec_provider.get`), and `mailsec_provider.set.mtd` or `mailsec_provider.set` | +| Create and enable a credential secret in one write | `secret.set` | +| Select existing secrets and read their metadata | `secret.get.mtd`; reading secret values separately needs `secret.get` | +| Test a connection | `mailsec.act` | +| Read messages and coverage | `mailsec.get` | +| Change mail rules or policy | `mailsec.set` | + +Deleting a connection additionally needs `mailsec_provider.del`. Read-only +analyst access does not grant permission to change which tenant or mailboxes +the product reads. ## 3. Prepare the provider credential @@ -82,6 +104,20 @@ always referenced, never inlined into the connection record. limacharlie mailsec onboarding --provider m365 --oid $OID ``` + Newer development builds can fill the Google commands in advance: + + ```bash + limacharlie mailsec onboarding --provider gworkspace \ + --project-id "$GCP_PROJECT" --sa-email "$SERVICE_ACCOUNT_EMAIL" \ + --topic mailsec-gmail-push --subscription mailsec-gmail-push-sub \ + --oid "$OID" --output yaml + ``` + + Set the two variables to the project and service-account email from your + downloaded key. If `--help` does not list these flags, send `project_id`, + `sa_email`, `topic` and `subscription` to `GET /onboarding` through the + [API command](api-reference.md#reads), or update the development CLI. + ## 4. Connect the mail tenant ### In the console @@ -127,10 +163,11 @@ ingest: backfill_days: 14 features: outbound_observation: true - reports_mailbox: phishing@corp.example ``` -Replace `pilot@corp.example` with your pilot mailbox addresses. Omitting `scope` +Replace `pilot@corp.example` with your pilot mailbox addresses. If you later +configure `features.reports_mailbox`, use an existing mailbox and include it +in this scope too; otherwise user reports cannot arrive. Omitting `scope` or leaving its include lists empty covers **every discovered mailbox**, subject to exclusions and any domain filter. `include_addresses` and `exclude_addresses` entries must contain `@`; `domains` entries must be bare domains containing a dot, diff --git a/docs/includes/code-security-cli-version.md b/docs/includes/code-security-cli-version.md new file mode 100644 index 000000000..d6c034ce3 --- /dev/null +++ b/docs/includes/code-security-cli-version.md @@ -0,0 +1,5 @@ +!!! note "CLI examples use the development CLI" + Stable `limacharlie` 5.6.2 does not yet contain the Code Security commands + below. Follow [CLI installation](https://docs.limacharlie.io/cloud-security/code-security/getting-started/#cli-installation), or + use the console and documented REST routes. A newer CLI does not enable + features that are unavailable in your organization's data region. diff --git a/docs/includes/code-security-cli.md b/docs/includes/code-security-cli.md new file mode 100644 index 000000000..9dfa53b04 --- /dev/null +++ b/docs/includes/code-security-cli.md @@ -0,0 +1,25 @@ +!!! note "Code Security CLI availability" + The latest stable `limacharlie` release, **5.6.2**, includes Cloud Security + posture commands but does **not** include `cloudsec code`, `cloudsec image`, + Code Security evidence or remediation commands, or the `--repo` / `--source` finding + filters. Those CLI examples currently require the development version of + the [public Python SDK](https://github.com/refractionPOINT/python-limacharlie). + Install it separately from your normal CLI: + + ```bash + python3 -m venv .venv-code-security + source .venv-code-security/bin/activate + python -m pip install --upgrade 'git+https://github.com/refractionPOINT/python-limacharlie.git@master' + limacharlie cloudsec code --help + ``` + + For repeatable scripts, replace `master` with a tested commit SHA and record + it with `python -m pip freeze`. Check the selected command's `--help` after + upgrading. You can also use the console or the documented REST routes with + the stable CLI's `limacharlie api` command. + + Installing a newer CLI does not enable a server capability. Hosted scanning + and advanced evidence features depend on availability in your organization's + data region. Check **Code security → Overview**, `code capabilities` and + `code status`; if you see `code_lane_not_enabled_in_datacenter`, contact + LimaCharlie before completing hosted-scan setup. diff --git a/snippets/python/cloudsec_findings.py b/snippets/python/cloudsec_findings.py new file mode 100644 index 000000000..e0c7473a6 --- /dev/null +++ b/snippets/python/cloudsec_findings.py @@ -0,0 +1,16 @@ +from limacharlie.client import Client +from limacharlie.sdk.organization import Organization +from limacharlie.sdk.cloudsec import CloudSec + +client = Client(oid="YOUR_OID", api_key="YOUR_API_KEY") +cs = CloudSec(Organization(client)) + +# Keep the filters identical when requesting each subsequent page. +cursor = None +while True: + page = cs.list_findings(severity=["CRITICAL"], kev=True, limit=100, cursor=cursor) + for finding in page.get("findings", []): + print(finding["lc_risk"], finding["title"], finding["resource_urn"]) + cursor = page.get("next_cursor") + if not cursor: + break From 0633b42c27a12ad920ddf10fafcdee550b1402e3 Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Wed, 30 Sep 2026 01:22:12 +0000 Subject: [PATCH 2/5] Document MailSec purpose classification and current rule evidence fields --- docs/email-security/detections.md | 7 +++ docs/email-security/messages.md | 11 +++++ docs/email-security/rule-reference.md | 71 +++++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/docs/email-security/detections.md b/docs/email-security/detections.md index cad015da2..0fa15ac40 100644 --- a/docs/email-security/detections.md +++ b/docs/email-security/detections.md @@ -8,6 +8,13 @@ and how to tune it. ## The verdict +The optional `mail_type` classification describes apparent purpose, such as +marketing or correspondence, independently of this verdict. A purpose label +does not establish safety or consent. `mail_type/type=unknown` is a classification +abstention; an absent `mail_type` means not classified. See +[Messages & Triage](messages.md) for viewing it and the +[rule reference](rule-reference.md#mailtypeinfo) for its paths. + | Verdict | Meaning | |---|---| | `malicious` | Score at or above the malicious threshold | diff --git a/docs/email-security/messages.md b/docs/email-security/messages.md index a840e7838..5b647255e 100644 --- a/docs/email-security/messages.md +++ b/docs/email-security/messages.md @@ -6,6 +6,17 @@ the ones that need a person. This page covers the queue, the drawer, the actions and the audit trail they leave. +Where classification is available, the queue and drawer show the message's +apparent purpose, such as **Correspondence**, **Transactional**, or **Marketing**. +This is separate from its security verdict: a transactional message can still be +malicious. **Not classified** means no classification is stored; **Unknown** means +the classifier abstained. The drawer explains the reasons when present. Inspect +the `mail_type` object, including its classifier version, with +`limacharlie mailsec message get MESSAGE_UUID --output yaml --oid $OID`, +`mailsec message list --output yaml`, or an `analyze` result. See the +[purpose fields](rule-reference.md#mailtypeinfo) for API and rule paths; purpose is +not a message-list filter. + ## The queue Filtering is **entirely server-side** — every filter below narrows the query in diff --git a/docs/email-security/rule-reference.md b/docs/email-security/rule-reference.md index df05ba3f4..e8cb83b3a 100644 --- a/docs/email-security/rule-reference.md +++ b/docs/email-security/rule-reference.md @@ -67,6 +67,8 @@ Scoring classes require `weight` from 1 to 100; graymail records must omit it. | Where would a reply go? | `headers/reply_to` (array of addresses), `sender/reply_to_mismatch` | | Did authentication fail? | `auth/spf/result`, `auth/dmarc/result`; scope `auth/dkim` for individual signatures | | What does the newest reply say? | `body/current_thread/text` or `body/current_thread/visible_text` | +| Does it claim to be a reply to a known conversation? | `body/is_reply`, `enrichments/thread_verification/known`, `enrichments/thread_verification/unverified_reply` | +| What kind of message does it appear to be? | `mail_type/type`; purpose classification is separate from the security verdict | | Does one link disguise its destination? | Scope `links`; compare `href_url/domain/root` and `mismatched` | | Is a link's domain new or suspicious? | Scope `enrichments/link_features`; read `domain`, `domain_age_days`, `popularity_bucket` | | Does an attachment match an IOC? | Scope `attachments`; read `sha256` or another hash | @@ -161,8 +163,34 @@ subject to parser and analysis depth limits. | `hops` | array of [Hop](#hop) | Non-empty | | `enrichments` | [Enrichments](#enrichments) | When set | | `verdict` | [VerdictInfo](#verdictinfo) | When set | +| `mail_type` | [MailTypeInfo](#mailtypeinfo) | When set | | `_meta` | [Meta](#meta) | When set | +### MailTypeInfo + +| Field | Type | Presence | +|---|---|---| +| `type` | string | Always | +| `reasons` | array of [MailTypeReason](#mailtypereason) | Always | +| `classifier_version` | string | Always | + +`type` describes apparent purpose: `correspondence`, `transactional`, +`notification`, `marketing`, `solicitation`, or `unknown`. It does not establish +safety, authenticity, consent, or whether a recipient wants the message. Keep +unfamiliar values when reading newer data. An absent `mail_type` means not +classified, including historical messages; `unknown` is an explicit abstention. +Neither should suppress threat evidence or authorize a response. + +Use `mail_type/type` in a `dr-mail` rule or `event/mail_type/type` in a platform +D&R rule on `EMAIL_MESSAGE`. Message-list filtering does not accept `mail_type`. + +### MailTypeReason + +| Field | Type | Presence | +|---|---|---| +| `code` | string | Always | +| `description` | string | Always | + ### Mailbox | Field | Type | Presence | @@ -268,12 +296,17 @@ subject to parser and analysis depth limits. | `plain` | [PlainBody](#plainbody) | When set | | `current_thread` | [ThreadSegment](#threadsegment) | When set | | `previous_threads` | array of [PreviousThread](#previousthread) | Non-empty | +| `is_reply` | boolean | Non-empty | | `ips` | array of string | Non-empty | | `has_remote_images` | boolean | Non-empty | | `hidden_text_present` | boolean | Non-empty | | `language` | string | Non-empty | | `truncated` | boolean | Non-empty | +`is_reply` records an unauthenticated header claim. Check +[ThreadVerification](#threadverification) before trusting the quoted history; +the pipeline includes the whole body in `current_thread` for an unverified reply. + ### HTMLBody | Field | Type | Presence | @@ -320,8 +353,15 @@ subject to parser and analysis depth limits. | `form_password_input` | boolean | Non-empty | | `rewritten_by` | string | Non-empty | | `rewritten_url` | string | Non-empty | +| `unverified_hint` | boolean | Non-empty | +| `hint_mismatch` | boolean | Non-empty | | `redirects_resolved` | array of string | Non-empty | +`unverified_hint` marks a destination derived from an author-controlled hint, +rather than decoded from a gateway wrapper. It is a lead to investigate, not +proof of where a click goes. `hint_mismatch` marks disagreement between that hint +and a decoded destination; when both links are emitted, it is set on both. + ### URLInfo | Field | Type | Presence | @@ -467,6 +507,7 @@ subject to parser and analysis depth limits. | `sender_domain` | [SenderDomain](#senderdomain) | When set | | `link_features` | array of [LinkFeature](#linkfeature) | Non-empty | | `lookalike` | [Lookalike](#lookalike) | When set | +| `thread_verification` | [ThreadVerification](#threadverification) | When set | | `password_in_body` | boolean | Non-empty | | `detonation` | [Detonation](#detonation) | When set | @@ -478,10 +519,16 @@ subject to parser and analysis depth limits. | `days_known` | integer | Non-empty | | `msg_count_30d` | integer | Non-empty | | `flagged_count_180d` | integer | Non-empty | +| `sparse_flagged_history` | boolean | Non-empty | +| `established_high_volume` | boolean | Non-empty | | `flagged_count_other_addresses_180d` | integer | Non-empty | | `prevalence` | string | Non-empty | | `profile_key` | string | Non-empty | +`established_high_volume` describes sustained sending history; +`sparse_flagged_history` qualifies that history with a low historical flag count. +Neither establishes safety or overrides content and authentication findings. + ### SenderDomain | Field | Type | Presence | @@ -498,9 +545,29 @@ subject to parser and analysis depth limits. | `domain_age_days` | integer | When set | | `popularity_bucket` | string | Non-empty | | `in_urlhaus` | boolean | Non-empty | +| `feed_lookup_skipped` | boolean | Non-empty | | `mixed_script` | boolean | Non-empty | | `credentials_in_url` | boolean | Non-empty | +When `feed_lookup_skipped` is true, that URL exceeded the per-message lookup +budget. An absent or false `in_urlhaus` then means it was not checked, rather than +a completed lookup with no hit. + +### ThreadVerification + +| Field | Type | Presence | +|---|---|---| +| `checked` | integer | Non-empty | +| `known` | boolean | Non-empty | +| `unverified_reply` | boolean | Non-empty | + +This optional block checks inbound reply references against mail the organization +participated in. `checked` counts bounded lookups; `known` means at least one +qualifying referenced message was found. A message from the same external sender +alone does not qualify. `unverified_reply` identifies an unsupported reply claim. +An absent block, or an omitted false boolean, does not prove the thread is safe; +lookup failure must not be treated as evidence against a message. + ### Lookalike | Field | Type | Presence | @@ -617,4 +684,8 @@ subject to parser and analysis depth limits. | Field | Type | Presence | |---|---|---| | `stage` | string | Always | +| `code` | string | Non-empty | | `message` | string | Always | + +When present, `code` is the stable identifier for a recovered failure. Prefer it +over matching the human-readable `message`, which may change. From 701a48ba4fc9fba461bc4b560795f0ce75871806 Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Wed, 30 Sep 2026 02:00:15 +0000 Subject: [PATCH 3/5] Document security product MCP profiles and pilot onboarding --- docs/6-developer-guide/mcp-server.md | 44 ++++++++- docs/cloud-security/api-reference.md | 4 +- docs/cloud-security/mcp.md | 133 +++++++++++++++++++-------- docs/email-security/index.md | 1 + docs/email-security/mcp.md | 124 +++++++++++++++++++++++++ mkdocs.yml | 1 + 6 files changed, 268 insertions(+), 39 deletions(-) create mode 100644 docs/email-security/mcp.md diff --git a/docs/6-developer-guide/mcp-server.md b/docs/6-developer-guide/mcp-server.md index 66843ed8d..2d8b05810 100644 --- a/docs/6-developer-guide/mcp-server.md +++ b/docs/6-developer-guide/mcp-server.md @@ -177,7 +177,16 @@ The MCP server enforces the same permission model as the LimaCharlie REST API. T ### Permission Enforcement -The API enforces permissions strictly. Any operation attempted without the required permission will fail with a `401` error that specifies the missing privilege. The AI assistant will surface these errors and indicate which permission is needed. +Organization-scoped MCP operations require `ai_agent.operate` by default, in +addition to the API permission for the requested operation. The server or API +reports missing privileges; an authentication failure and a permission denial +are different problems. Read the returned error before changing credentials. + +Profiles select the tools offered and callable on an endpoint; they do not grant +permissions. Prefer a product's read-only profile with a read-only key for a first +review. New profiles require a server version that includes them; an unknown +profile endpoint can return 404. Inspect the tool list because a server-wide +configured profile can override the URL profile. ### Recommended Permissions by Use Case @@ -239,6 +248,37 @@ For full platform management (includes all of the above, plus): | `cloudsensor.get`, `cloudsensor.set`, `cloudsensor.del` | Manage cloud sensor adapters | | `externaladapter.get`, `externaladapter.set`, `externaladapter.del` | Manage external adapters | +#### CloudSec, CodeSec and MailSec + +Start with a small, read-only product review, then grant the particular write +permission only when the workflow needs it: + +| Workflow | Profile | Permissions beyond `ai_agent.operate` | +|---|---|---| +| CloudSec posture and CodeSec findings | `cloud_security_readonly` | `cloudsec.get` | +| CloudSec triage and code ingest | `cloud_security` | `cloudsec.get`, `cloudsec.set` | +| Dependency AutoFix and remediation run creation/decision | `cloud_security` | `cloudsec.respond` (separate from `cloudsec.set`) | +| MailSec coverage, messages, campaigns and histories | `email_security_readonly` | `mailsec.get` | +| Raw email download | `email_security` | `mailsec.get` and `mailsec.get.eml` | +| MailSec EML analysis, rule validation/backtest and selected bulk preview | `email_security_readonly` | `mailsec.get` | +| MailSec provider diagnostics, campaign preview, verdict revision or remediation | `email_security` | `mailsec.act` | +| MailSec report resolution/reopening | `email_security` | `mailsec.set` | +| Product provider/policy/secret setup | `platform_admin` | Dedicated provider `.get/set`, product `.get/set` for policy, `secret.set` and required metadata-read access | + +CloudSec requires the `ext-cloud-security` subscription; MailSec requires +`ext-email-security` and applicable beta access. Setup uses generic Hive and +extension tools, the console or CLI; product read-only profiles exclude those +writes. MailSec's read-only profile excludes raw EML and privileged diagnostics. +Backend capability rollout remains independent of the client version. + +Use `https://mcp.limacharlie.io/mcp/cloud_security_readonly` or +`https://mcp.limacharlie.io/mcp/email_security_readonly` for a supported hosted +profile. With a local server, select the same name using `MCP_PROFILE`. +Follow [CloudSec in your IDE](../cloud-security/mcp.md), +[MailSec with an AI assistant](../email-security/mcp.md), or the +[MCP source onboarding guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/SECURITY-PRODUCTS.md) +for pilot setup and first tools. + ### Assigning Permissions **For users (OAuth/JWT):** @@ -273,6 +313,8 @@ Once connected, AI assistants can: - **Take response actions** — Isolate endpoints, kill processes, manage tags - **Search threat intelligence** — Query IOCs and map to MITRE ATT&CK - **Configure the platform** — Manage outputs, adapters, secrets, and playbooks +- **Review CloudSec and CodeSec** — Inspect posture, repositories, findings and coverage +- **Triage MailSec** — Review coverage, messages, campaigns and action history --- diff --git a/docs/cloud-security/api-reference.md b/docs/cloud-security/api-reference.md index a97b853fc..2d3a1f20c 100644 --- a/docs/cloud-security/api-reference.md +++ b/docs/cloud-security/api-reference.md @@ -96,7 +96,9 @@ One route sits outside the `{oid}` path — the MSSP cross-tenant board: ## Writes -All writes are `POST` with a JSON body and require `cloudsec.set`. +The writes below use `POST` with a JSON body. Ordinary configuration, triage and +ingest writes require `cloudsec.set`; Code Security AutoFix instead requires +`cloudsec.respond` and creates a governed remediation run. | Route | Body | Returns | |---|---|---| diff --git a/docs/cloud-security/mcp.md b/docs/cloud-security/mcp.md index 001944436..63316d3cd 100644 --- a/docs/cloud-security/mcp.md +++ b/docs/cloud-security/mcp.md @@ -5,7 +5,9 @@ Security to any [Model Context Protocol](https://modelcontextprotocol.io/) clien Cursor, and others — so an AI assistant can read your cloud posture, triage findings, and, for [Code Security](code-security/index.md), scan the working copy on your own machine before anything is pushed. -This page covers the setup and the Code Security tools. Most of the other Cloud Security tools +This page covers the setup and the Code Security tools. Tool availability depends +on the MCP server version and backend rollout; check your client's tool list. +Most of the other Cloud Security tools match a [command line interface](cli.md) command. ## Setup — Claude Code @@ -15,20 +17,22 @@ git clone https://github.com/refractionPOINT/lc-mcp-server cd lc-mcp-server go build -o lc-mcp-server ./cmd/server -claude mcp add limacharlie-cloudsec \ - --env LC_OID= \ - --env LC_API_KEY= \ +claude mcp add \ + --env LC_OID=YOUR_ORGANIZATION_UUID \ + --env LC_API_KEY=YOUR_API_KEY \ --env MCP_MODE=stdio \ - --env MCP_PROFILE=cloud_security \ + --env MCP_PROFILE=cloud_security_readonly \ + --transport stdio limacharlie-cloudsec \ -- /absolute/path/to/lc-mcp-server ``` -`/mcp` in a session lists the server and its tools. +Build with the Go version required by the server's `go.mod` (currently 1.27.1). +`/mcp` in a session lists the server and its tools. The command follows the +[Claude Code MCP setup](https://code.claude.com/docs/en/mcp). ## Setup — Cursor -Add the server to `~/.cursor/mcp.json`, or to `.cursor/mcp.json` inside a project to scope the -credential to one repository: +Add the server to your personal `~/.cursor/mcp.json`: ```json { @@ -40,7 +44,7 @@ credential to one repository: "LC_OID": "", "LC_API_KEY": "", "MCP_MODE": "stdio", - "MCP_PROFILE": "cloud_security", + "MCP_PROFILE": "cloud_security_readonly", "LOG_LEVEL": "warn" } } @@ -58,17 +62,33 @@ stderr is noise in the client's transport log. | Profile | What it exposes | |---|---| | `cloud_security` | Every Cloud Security tool, including the triage writes | -| `cloud_security_readonly` | The reads only — for a session that must not be able to change anything | +| `cloud_security_readonly` | CloudSec reads, excluding local scan, ingest, triage and response writes | | `all` | The whole platform | +Profiles select callable tools; they do not grant API permissions. Generic +provider, secret and policy setup uses `platform_admin` tools or the +[console/CLI setup](setup-cli.md). Keep your key's permissions scoped to the +workflow even when changing profiles. The hosted profile endpoint is +`https://mcp.limacharlie.io/mcp/cloud_security_readonly` when that deployment +supports it; verify the returned tools and any server-wide profile override. An +unrecognized profile endpoint can return 404. + A narrow profile is not just tidiness. An assistant chooses from what it is shown, so a session that only needs to read posture is both cheaper and safer with `cloud_security_readonly`. ## Permissions -Reads need `cloudsec.get`. The triage writes, code ingest and AutoFix need `cloudsec.set`. The whole +Organization-scoped tools require `ai_agent.operate` by default. Reads need +`cloudsec.get`. Triage writes and code ingest need +`cloudsec.set`; dependency AutoFix, remediation run creation and decisions require the separate +`cloudsec.respond` permission. The whole surface also requires the organization to be subscribed to the `ext-cloud-security` extension — a -403 saying cloud security is not enabled means exactly that, and the tools say so in their errors. +403 may indicate a missing subscription or permission. Check the error before +changing configuration. + +For a first review, ask the assistant to use `cloudsec_get_scan_status`, +`cloudsec_get_overview`, then `cloudsec_list_findings` for high-severity open +findings. Read collection and scanner coverage before interpreting an empty list. ## The Code Security tools @@ -77,10 +97,19 @@ surface also requires the organization to be subscribed to the `ext-cloud-securi | `cloudsec_code_repos` | The repositories the code lane sees, with scan state and the open-finding rollup | | `cloudsec_code_findings` | Findings for one or more repositories, or the cross-filtered facet counts | | `cloudsec_code_fixes` | The dependency upgrades that close the most findings, each with a finding id to pass to `cloudsec_code_autofix` | -| `cloudsec_code_capabilities` | What each GitHub connection can do: scanning, pull-request checks, comments and AutoFix | +| `cloudsec_code_capabilities` | Per-connection scanning and write capabilities; GitLab/Bitbucket workflow support depends on rollout | | `cloudsec_code_scan_local` | Scans a working copy on your machine with the same scanner the hosted lane runs | | `cloudsec_code_autofix` | Opens the dependency fix pull request for an SCA finding | +Additional tools read build provenance (`cloudsec_code_provenance`), finding +evidence (`cloudsec_get_finding_evidence_chain`), scanner coverage +(`cloudsec_get_code_coverage`) and change impact (`cloudsec_get_code_impact`). +Their availability depends on the backend capability; missing or stale evidence +does not prove safety. Provenance pushes require `cloudsec.set` and contain +metadata, not source code. Remediation run tools require `cloudsec.respond`. +See the [server's product guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/SECURITY-PRODUCTS.md) +and the actual tool schema for selectors and confirmation requirements. + ### Before they can return anything Code scanning is opt-in, and two things must be true: @@ -130,17 +159,31 @@ the inventory. cloudsec_code_scan_local { "path": "/home/me/src/api" } ``` -This runs on **your** machine, not in LimaCharlie: it needs Docker and a current -[`limacharlie` CLI](cli.md) on PATH, and it takes minutes rather than seconds. Nothing about the -checkout leaves the machine, and without `ingest` nothing leaves it at all — the result says so -explicitly, so a scan that found plenty is not misread as a clean estate. +This runs on the machine hosting your local server: the default container path +needs Docker and a +development [`limacharlie` CLI with CodeSec support](code-security/getting-started.md#cli-installation) +on PATH, and it takes minutes rather than seconds. PyPI 5.6.2 lacks the code scan +command. Verify `limacharlie cloudsec code scan --help` before starting. The default +scanner image also requires registry access; an anonymous pull is not sufficient. +Newer MCP builds let the operator set `LC_CODE_SCANNER_IMAGE` or +`LC_CODE_SCANNER_BINARY` for a compatible authorized image or local executable. +These map to the CLI's `--image` / `--binary`; use a development CLI containing +those flags until release. An MCP caller cannot select the executable. Inspect +the server's [local scan guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/CLOUD-SECURITY-CODE.md). + +Without `ingest`, the findings report is not uploaded to LimaCharlie. Image pulls, +scanner dependency/intelligence lookups and optional rule downloads may still use +the network. A local scan is not visible in the hosted estate until ingested. Because it runs a container locally, it is available only when the server is running in stdio mode. A hosted MCP deployment refuses it. -`scanners` defaults to `sca,iac,licenses`; `sast` and `images` also run locally. Local `sast` never -applies your organization's code rules. It runs the rules built into the scanner image the CLI uses by -default, and reports `sast_no_rules` with a scanner that has no built-in rules (see +`scanners` defaults to `sca,iac,licenses`; `sast` and `images` also run locally. +By default SAST uses scanner-local rules and does not automatically load +organization rules; the delegated local-only CLI has no organization credentials. +Newer MCP builds let the operator set `LC_CODE_SCANNER_RULES_FILE` to a compatible +exported code-rule JSON file, forwarding the CLI's `--rules-file`. An MCP caller +cannot choose the rules file. A scanner with no usable rules reports `sast_no_rules` (see [Scan locally or in CI](code-security/bring-your-own-scanner.md#scan-locally-or-in-ci)). **Secret scanning does not**, and asking for it is an error rather than a silent omission: a credential's identity in this pipeline is a digest keyed by a value only the hosted lane holds, so locally-found secrets @@ -171,29 +214,45 @@ backend resolves it against the dependency rows its own scan produced and raises that package to that advisory's fixed version, so there is no way to name a package or a version. `repo` and `provider` are optional search hints. -It needs the connection's GitHub App to hold **Contents: Read and write** and **Pull requests: -Read and write**. `cloudsec_code_capabilities` shows whether it does. +For GitHub it needs **Contents: Read and write** and **Pull requests: Read and write** +App permissions. GitLab.com/Bitbucket use separately configured write credentials +when their workflow is available. `cloudsec_code_capabilities` reports configured +capabilities; a tenant policy cannot enable an unavailable workflow. -The tool answers as soon as the request is **accepted**; the clone, the edit and -the pull request happen minutes later in a sandbox, so **the pull request is the -result**. Read it in the repository rather than in the tool's reply. +The tool creates a governed `open_fix_pr` remediation run and returns its +`run_id` and `state`. It requires `cloudsec.respond`; the caller is recorded as +requester and approver. Follow the run with `cloudsec_get_remediation` before +reporting an outcome. The clone, edit and PR happen asynchronously; `accepted` +does not mean a PR exists or the vulnerability is fixed. Repeating a request +before the PR opens can return the same run with `replayed: true`. -!!! warning "A refusal does not come back on this call" - Because the call has already answered, every reason a fix does not happen is - a quiet no-op here: an App that is not installed on the repository or cannot write - (`write_app_not_configured`), one lacking `Contents: Read and write` - (`write_app_lacks_contents`), a package - flagged malicious, no published fixed version, an unsupported ecosystem, a - repository outside the policy scope or over the free-tier quota, a pull - request already open for that package, or the daily limit. - - None of these appear in the reply. They surface as the - `cloudsec.code_autofix_refused` operational event, once operational events - are turned on with the `emission` policy's `ops_events`. +A disabled workflow is refused immediately. Later failures, such as missing +write permissions, policy scope, unsupported edits, an existing PR or exhausted +budgets, appear in the run's `failure_reason` and operational events. `change` +records the PR; `verified` means the fix was observed in every in-scope +deployment. Missing deployment evidence cannot establish a verified fix. See [AutoFix pull requests](code-security/autofix.md) for the setup and the lockfile behavior that decides whether the pull request is complete on its own. +## Local IaC attribution + +Newer builds provide `cloudsec_code_iac_map_extract` in the full CloudSec profile +for local STDIO sessions. The operator must explicitly set `LC_IAC_MAP_EXTRACTOR` +to an installed extractor's path; there is no implicit executable selection. +The tool reads a local Terraform/OpenTofu show-JSON file and returns sanitized +identity/allowlisted desired metadata. Raw plans, state, source and credentials +are not uploaded. Review the sanitized document before a separate +`cloudsec_code_iac_map_push` call. + +Push and receipt status both require `cloudsec.set`, so +`cloudsec_code_iac_map_status` is excluded from the read-only profile despite +being a read. A `processing` receipt is not published evidence; check status +until `published`, or resubmit the same document only for a retryable receipt. +Publication is not proof of deployment or remediation. See +[IaC source mapping](code-security/containment-setup.md#terraform-maps) +and the tool schema for exact receipt fields and capability prerequisites. + ## See also - [Code Security](code-security/index.md) — the product these tools read diff --git a/docs/email-security/index.md b/docs/email-security/index.md index 194b7805d..cfae262f7 100644 --- a/docs/email-security/index.md +++ b/docs/email-security/index.md @@ -27,6 +27,7 @@ it at the provider. | **User reports** | An abuse mailbox becomes an SLA queue: reports are joined back to the original message across the whole tenant, robots that mail the abuse address are auto-resolved out of the queue, and reporters can be sent a templated acknowledgement. | | **Telemetry** | `EMAIL_MESSAGE`, `EMAIL_VERDICT` (every verdict decision — the engine's own at ingest, then each override), `EMAIL_ACTION`, `EMAIL_USER_REPORT` and `EMAIL_INGEST_ERROR` land in the same lake as your EDR, cloud and identity telemetry — so "phish delivered, then that user's endpoint ran a new binary" is one D&R rule. | | **Configuration as data** | Connections, policy and custom rules are Hive records, so everything is API-first and git-syncable from day one. | +| **AI assistant access** | [MCP tools](mcp.md) for read-only coverage and triage, with separately permissioned diagnostics and responses. Requires a server version containing MailSec support. | ## What it does not do diff --git a/docs/email-security/mcp.md b/docs/email-security/mcp.md new file mode 100644 index 000000000..2f6571b76 --- /dev/null +++ b/docs/email-security/mcp.md @@ -0,0 +1,124 @@ +# MailSec with an AI assistant (MCP) + +--8<-- "includes/email-security-beta.md" + +The [LimaCharlie MCP server](https://github.com/refractionPOINT/lc-mcp-server) +lets an AI assistant review MailSec coverage, messages, campaigns and action +history. Start with a read-only session and one pilot mailbox. New MailSec tools +require a server build containing the `email_security` profiles; installed and +hosted versions may not include them yet. Check your client's tool list before +using the examples below. A newer client cannot enable an unavailable backend +feature or grant product access. + +## Connect a read-only session + +Create an organization API key with `ai_agent.operate` and `mailsec.get`. Use the +organization's UUID, not its name. For hosted OAuth or organization-key setup, +see [Connecting AI Assistants](../6-developer-guide/mcp-server.md). A supported +hosted profile is `https://mcp.limacharlie.io/mcp/email_security_readonly`; +inspect the returned tools and any server-wide profile override. An unrecognized +profile endpoint can return 404. Keep the key's permissions read-only too. + +For a local [Claude Code client](https://code.claude.com/docs/en/mcp), build the +public server with the Go version in its `go.mod` (currently Go 1.27.1): + +```bash +git clone https://github.com/refractionPOINT/lc-mcp-server +cd lc-mcp-server +go build -o lc-mcp-server ./cmd/server + +claude mcp add \ + --env LC_OID=YOUR_ORGANIZATION_UUID \ + --env LC_API_KEY=YOUR_API_KEY \ + --env MCP_MODE=stdio \ + --env MCP_PROFILE=email_security_readonly \ + --transport stdio limacharlie-mailsec \ + -- /absolute/path/to/lc-mcp-server +``` + +Inspect `/mcp` after connecting. For Cursor, use the +[CloudSec JSON example](../cloud-security/mcp.md#setup-cursor), changing +`MCP_PROFILE` to `email_security_readonly` and the server name to +`limacharlie-mailsec`. Keep credentials in personal client configuration. + +The read-only profile contains `mailsec.get` operations, including EML sample +analysis, candidate validation/backtests and selected bulk previews. It excludes +raw EML download, provider diagnostics, campaign preview, verdict revisions and +responses. Profiles select tools; each API still checks its own permissions. + +## Connect a pilot mailbox + +First subscribe to `ext-email-security` through the console, CLI or administration +profile's `subscribe_to_extension`. Every MailSec endpoint, including onboarding +instructions, requires the subscription and beta access. + +Then use `mailsec_get_onboarding` with `provider: "m365"` or `"gworkspace"` to read +current setup requirements. Workspace parameters `project_id`, `sa_email`, +`topic` and `subscription` fill customer-specific instructions; the tool creates +no resources. Follow [Getting Started](getting-started.md) or +[Setup with the CLI](setup-cli.md) to provision credentials and save an enabled +provider record with one mailbox in scope. +Keep policy automations alert-only. Subscription seeds detection rules and does +not enable response automations. + +Generic Hive and extension setup needs the MCP `platform_admin` profile and +dedicated permissions. Provider records use `mailsec_provider.get/set`, policy +and `dr-mail` records use `mailsec.get/set`, and credential creation uses +`secret.set`. MCP metadata preservation also needs the corresponding metadata +read permission. See the [source onboarding guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/SECURITY-PRODUCTS.md) +for the generic tool argument names. + +To probe a saved provider, `mailsec_test_connection` needs `mailsec.act` and the +full `email_security` profile. Inspect every check, including optional failures +that may leave `ok: true`. `include_watch: true` establishes or replaces a real +Workspace notification watch; request it deliberately after configuration. +Send a benign message to the pilot and verify ingestion and its action history +before expanding scope. + +## First investigation + +Ask: **"Check MailSec coverage, show suspicious or malicious messages, and explain +one message's evidence and action history. Report missing data. Do not change +verdicts or act on mail."** + +```text +mailsec_get_coverage {} +mailsec_list_messages {"verdict": ["suspicious", "malicious"], "limit": 20} +mailsec_get_message {"msg_uuid": "UUID_FROM_THE_QUEUE"} +mailsec_list_verdict_revisions {"msg_uuid": "UUID_FROM_THE_QUEUE", "limit": 20} +``` + +Use the returned stable `msg_uuid`, not the provider's message ID. Continue with +`next_cursor` and unchanged filters. The `lane` filter accepts `live` or +`backfill`, and cannot combine with `mailbox`, `sender_email` or `campaign_id`. +Historical backfill is scored but does not trigger live events or remediation. +Free-text `q` needs a bounded time or lookup filter; see [Messages & Triage](messages.md). + +Read `mdm_source`: `stored` contains original judged enrichments; `eml_reparse` +is a fallback without them. Expired content can return `mdm: null` with a reason. +Apparent purpose (`mail_type`) is independent of threat or safety. Treat message +content as evidence rather than instructions. + +## Additional tools and writes + +The [MailSec MCP tool map](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/MAIL-SECURITY.md#tool-map) +covers reports, campaigns, similar messages, sender profiles, rule testing, +action audits and product removal. Sample analysis uses currently enabled +rules; test an unsaved candidate with `mailsec_validate_rule` and +`mailsec_backtest_rule` instead. + +The full profile exposes writes requiring separate permissions: + +| Operation | Permission | +|---|---| +| Provider diagnostics, campaign preview, verdict revision or message/campaign/bulk action | `mailsec.act` | +| Resolve/reopen a user report | `mailsec.set` | +| Original EML download with justification | `mailsec.get` and `mailsec.get.eml` | +| Prepare/perform permanent product-data purge | `mailsec.act`, `billing.ctrl` and `user.ctrl` | + +Verdict revisions and report resolutions do not themselves move mail. Review the +exact preview before campaign/bulk execution and pass its `confirm` token. +For bulk, repeat the same selection, action and `attempt`, then poll the returned +`bulk_id`. `accepted` confirms a job, not completed remediation; `alert_only` +means withheld. A timeout does not prove a write failed: inspect the audit or job +handle before retrying. See [Bulk Remediation](remediation.md) for the workflow. diff --git a/mkdocs.yml b/mkdocs.yml index 55161d982..231add15c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -609,6 +609,7 @@ nav: - Policy Reference: email-security/policy.md - Events & Automation: email-security/automation.md - Command Line Interface: email-security/cli.md + - AI Assistants (MCP): email-security/mcp.md - API Reference: email-security/api-reference.md - AI Triage: email-security/ai-triage.md - Troubleshooting: email-security/troubleshooting.md From 55e45158d8bfb2e5a92f60a5e3fed66deebf629f Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Wed, 30 Sep 2026 03:08:37 +0000 Subject: [PATCH 4/5] Use standard CLI releases throughout security onboarding --- docs/6-developer-guide/mcp-server.md | 3 +-- docs/6-developer-guide/sdks/python-sdk.md | 18 ++++++-------- docs/cloud-security/cli.md | 24 ++++--------------- .../code-security/bring-your-own-scanner.md | 5 +--- docs/cloud-security/code-security/results.md | 2 +- .../code-security/troubleshooting.md | 2 +- docs/cloud-security/mcp.md | 24 +++++++++---------- docs/cloud-security/provider-setup/entra.md | 10 +++----- docs/cloud-security/remediation-sla.md | 4 ---- docs/email-security/ai-triage.md | 21 +++++----------- docs/email-security/mcp.md | 9 ++++--- docs/email-security/messages.md | 7 ++---- docs/email-security/policy.md | 2 +- docs/email-security/setup-cli.md | 6 ++--- docs/includes/code-security-cli-version.md | 9 ++++--- docs/includes/code-security-cli.md | 20 ++++------------ docs/includes/email-security-beta.md | 14 ++++------- 17 files changed, 57 insertions(+), 123 deletions(-) diff --git a/docs/6-developer-guide/mcp-server.md b/docs/6-developer-guide/mcp-server.md index 2d8b05810..536f5034f 100644 --- a/docs/6-developer-guide/mcp-server.md +++ b/docs/6-developer-guide/mcp-server.md @@ -184,8 +184,7 @@ are different problems. Read the returned error before changing credentials. Profiles select the tools offered and callable on an endpoint; they do not grant permissions. Prefer a product's read-only profile with a read-only key for a first -review. New profiles require a server version that includes them; an unknown -profile endpoint can return 404. Inspect the tool list because a server-wide +review. An unknown profile endpoint can return 404. Inspect the tool list because a server-wide configured profile can override the URL profile. ### Recommended Permissions by Use Case diff --git a/docs/6-developer-guide/sdks/python-sdk.md b/docs/6-developer-guide/sdks/python-sdk.md index 3096ad781..5fb51a087 100644 --- a/docs/6-developer-guide/sdks/python-sdk.md +++ b/docs/6-developer-guide/sdks/python-sdk.md @@ -715,10 +715,9 @@ response = ext.request( ### Cloud Security -The stable SDK exposes `CloudSec` through `limacharlie.sdk.cloudsec`. The +The SDK exposes `CloudSec` through `limacharlie.sdk.cloudsec`. The organization must be subscribed to Cloud Security; reading findings requires -`cloudsec.get`. This example targets SDK **5.6.2** and follows every page while -keeping its filters unchanged: +`cloudsec.get`. This example follows every page while keeping its filters unchanged: ```python --8<-- "snippets/python/cloudsec_findings.py" @@ -733,14 +732,11 @@ fields. ### Code Security and Email Security availability -Stable SDK 5.6.2 does **not** contain Code Security's SDK methods or the -`Mailsec` wrapper. Those interfaces are available in the development version -of the [public Python SDK](https://github.com/refractionPOINT/python-limacharlie). -Use a separate environment and pin a tested commit for automation. Follow -[Code Security CLI installation](../../cloud-security/code-security/getting-started.md#cli-installation) -or [Email Security setup](../../email-security/setup-cli.md) before copying -examples. Installing the development SDK does not enable server capabilities -or grant beta access. +Install or upgrade the SDK with `python -m pip install --upgrade limacharlie`. +Use `CloudSec` for Cloud Security and Code Security, and `Mailsec` for Email +Security. Follow [Code Security setup](../../cloud-security/code-security/getting-started.md) +or [Email Security setup](../../email-security/setup-cli.md) to configure the +product subscription, provider connection and permissions. Email Security requires its extension subscription and separates reading (`mailsec.get`), policy/triage edits (`mailsec.set`), provider actions diff --git a/docs/cloud-security/cli.md b/docs/cloud-security/cli.md index a26e61c11..84742cfb3 100644 --- a/docs/cloud-security/cli.md +++ b/docs/cloud-security/cli.md @@ -187,16 +187,10 @@ applies to `finding list`, `finding facets`, `finding causes`, and that defaults to **ascending** (soonest deadline first), keeping findings with no due date last rather than dropping them. -!!! note "SLA filters require CLI 5.6.2 or later" - The SLA selector and the `due_at` sort key are available in `limacharlie` - 5.6.2. On an older CLI, use the `sla=` and `sort=due_at` - parameters on the [REST route](api-reference.md#reads) — the server-side - feature is live either way. - The other lists carry a subset, so check `--help` before assuming a flag is there. `caasm coverage` behaves like `finding list` (repeatable filters, -`--sort`/`--order`, paging). `inventory list` and `caasm assets` page but do -not sort, and inventory's `--type` / `--provider` / `--account` / `--region` +`--sort`/`--order`, paging). `caasm assets` supports paging and `--sort urn` or `--sort last_seen`. +`inventory list` pages without sorting, and inventory's `--type` / `--provider` / `--account` / `--region` each take a single value rather than repeating. `attack-path list` returns the headline set in one shot: repeatable filters and `-q`, but no sorting and no paging. @@ -221,18 +215,10 @@ the returned sample, and `simulate resources` takes a repeatable `--resource-type` to narrow the walked types the way an exclusions rule does. `policy suggest` takes `--limit` (default 20, cap 50). -## Additional development CLI selectors - -The following additions are newer than stable 5.6.2. Use the development CLI -installation above and check each command's `--help`; older development -checkouts may not contain them yet. The corresponding REST selectors are in -the [API reference](api-reference.md). +## Additional selectors -The current additions are tracked in the -[public SDK update](https://github.com/refractionPOINT/python-limacharlie/pull/408). -Until that update is merged, installing `master` does not include every new -selector in this table; use the REST route or wait for the updated development -CLI before copying those flags. +These selectors are available in the CLI. Check each command's `--help` for +usage; the corresponding REST selectors are in the [API reference](api-reference.md). | Command | Additional selectors | |---|---| diff --git a/docs/cloud-security/code-security/bring-your-own-scanner.md b/docs/cloud-security/code-security/bring-your-own-scanner.md index 47e852071..b995b702d 100644 --- a/docs/cloud-security/code-security/bring-your-own-scanner.md +++ b/docs/cloud-security/code-security/bring-your-own-scanner.md @@ -154,10 +154,7 @@ jobs: - uses: actions/checkout@v4 - name: Install the LimaCharlie CLI - # Code Security commands are not in stable 5.6.2. This public SDK - # revision contains the commands and static-analysis rule options. - # Update the pin deliberately after testing your workflow. - run: pipx install 'git+https://github.com/refractionPOINT/python-limacharlie.git@e40d0889ff3271e2c5670fff8358b257b5cc404c' + run: pipx install limacharlie - name: Scan and push env: diff --git a/docs/cloud-security/code-security/results.md b/docs/cloud-security/code-security/results.md index 460844d4a..f453d2f26 100644 --- a/docs/cloud-security/code-security/results.md +++ b/docs/cloud-security/code-security/results.md @@ -60,7 +60,7 @@ installation, the drawer says so and links to the installation page. Select an image to open its findings in Risks. **Registries** groups images by image repository. -From the development CLI: +From the CLI: ```bash limacharlie cloudsec image repos diff --git a/docs/cloud-security/code-security/troubleshooting.md b/docs/cloud-security/code-security/troubleshooting.md index c61adc070..de5e19d6a 100644 --- a/docs/cloud-security/code-security/troubleshooting.md +++ b/docs/cloud-security/code-security/troubleshooting.md @@ -73,7 +73,7 @@ if it is shown. It names what is not set up and links to the fix. From the CLI, | Problem | What to check | |---|---| -| `No such command` for `cloudsec code` | Stable 5.6.2 does not include this group. Use the [development CLI installation](getting-started.md#cli-installation), or the console / REST routes. | +| `No such command` for `cloudsec code` | Upgrade with `python -m pip install --upgrade limacharlie` and confirm [CLI setup](getting-started.md#cli-installation). | | The CLI cannot identify the repository | Pass `--repo /`. | | Docker is not found | Install and start Docker, or use `--binary`, or push results from your own scanner with `code ingest`. | | A pushed repository is not recorded | It must match an enabled code-scanning policy and fit within the repository limits. | diff --git a/docs/cloud-security/mcp.md b/docs/cloud-security/mcp.md index 63316d3cd..8d3d0b29d 100644 --- a/docs/cloud-security/mcp.md +++ b/docs/cloud-security/mcp.md @@ -5,8 +5,8 @@ Security to any [Model Context Protocol](https://modelcontextprotocol.io/) clien Cursor, and others — so an AI assistant can read your cloud posture, triage findings, and, for [Code Security](code-security/index.md), scan the working copy on your own machine before anything is pushed. -This page covers the setup and the Code Security tools. Tool availability depends -on the MCP server version and backend rollout; check your client's tool list. +This page covers the setup and the Code Security tools. Check your client's tool +list after connecting. Most of the other Cloud Security tools match a [command line interface](cli.md) command. @@ -160,16 +160,14 @@ cloudsec_code_scan_local { "path": "/home/me/src/api" } ``` This runs on the machine hosting your local server: the default container path -needs Docker and a -development [`limacharlie` CLI with CodeSec support](code-security/getting-started.md#cli-installation) -on PATH, and it takes minutes rather than seconds. PyPI 5.6.2 lacks the code scan -command. Verify `limacharlie cloudsec code scan --help` before starting. The default -scanner image also requires registry access; an anonymous pull is not sufficient. -Newer MCP builds let the operator set `LC_CODE_SCANNER_IMAGE` or +needs Docker and the [`limacharlie` CLI](code-security/getting-started.md#cli-installation) +on PATH, and it takes minutes rather than seconds. Install or upgrade with +`python -m pip install --upgrade limacharlie`. The default scanner image requires +registry access. The operator can set `LC_CODE_SCANNER_IMAGE` or `LC_CODE_SCANNER_BINARY` for a compatible authorized image or local executable. -These map to the CLI's `--image` / `--binary`; use a development CLI containing -those flags until release. An MCP caller cannot select the executable. Inspect -the server's [local scan guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/CLOUD-SECURITY-CODE.md). +These map to the CLI's `--image` / `--binary`; an MCP caller cannot select the +executable. Inspect the server's +[local scan guide](https://github.com/refractionPOINT/lc-mcp-server/blob/master/docs/CLOUD-SECURITY-CODE.md). Without `ingest`, the findings report is not uploaded to LimaCharlie. Image pulls, scanner dependency/intelligence lookups and optional rule downloads may still use @@ -181,7 +179,7 @@ A hosted MCP deployment refuses it. `scanners` defaults to `sca,iac,licenses`; `sast` and `images` also run locally. By default SAST uses scanner-local rules and does not automatically load organization rules; the delegated local-only CLI has no organization credentials. -Newer MCP builds let the operator set `LC_CODE_SCANNER_RULES_FILE` to a compatible +The operator can set `LC_CODE_SCANNER_RULES_FILE` to a compatible exported code-rule JSON file, forwarding the CLI's `--rules-file`. An MCP caller cannot choose the rules file. A scanner with no usable rules reports `sast_no_rules` (see [Scan locally or in CI](code-security/bring-your-own-scanner.md#scan-locally-or-in-ci)). **Secret scanning @@ -237,7 +235,7 @@ lockfile behavior that decides whether the pull request is complete on its own. ## Local IaC attribution -Newer builds provide `cloudsec_code_iac_map_extract` in the full CloudSec profile +The server provides `cloudsec_code_iac_map_extract` in the full CloudSec profile for local STDIO sessions. The operator must explicitly set `LC_IAC_MAP_EXTRACTOR` to an installed extractor's path; there is no implicit executable selection. The tool reads a local Terraform/OpenTofu show-JSON file and returns sanitized diff --git a/docs/cloud-security/provider-setup/entra.md b/docs/cloud-security/provider-setup/entra.md index 2f2a479a8..6edb4f8df 100644 --- a/docs/cloud-security/provider-setup/entra.md +++ b/docs/cloud-security/provider-setup/entra.md @@ -232,7 +232,7 @@ upload the new one. ### Without the web app -The stable CLI's API command generates the certificate without requiring you to +The CLI's API command generates the certificate without requiring you to manage a JWT yourself: ```bash @@ -244,18 +244,14 @@ limacharlie api "/v1/cloudsec/$OID/providers/m365/certificate" \ jq -r .certificate certificate-response.json | base64 --decode > entra-prod.cer ``` -Development CLI builds with `cloudsec provider m365-certificate` offer the same -operation and write the public certificate directly: +The dedicated CLI command writes the public certificate directly: ```bash limacharlie cloudsec provider m365-certificate entra-prod \ --out entra-prod.cer --oid "$OID" --output yaml ``` -Stable 5.6.2 does not include this dedicated command; use `api` above or check -the development command's `--help` before running it. The dedicated command is -in the [public SDK update](https://github.com/refractionPOINT/python-limacharlie/pull/408); -use `api` while that update is pending. Both forms require +Both forms require `cloudsec.set` and `secret.set`. A repeat returns the existing certificate. `--replace` (API `replace: true`) immediately replaces the stored private key; an existing connection may stop authenticating until you upload the new public diff --git a/docs/cloud-security/remediation-sla.md b/docs/cloud-security/remediation-sla.md index d05434cc6..4b97093f1 100644 --- a/docs/cloud-security/remediation-sla.md +++ b/docs/cloud-security/remediation-sla.md @@ -259,10 +259,6 @@ usual worklist fields. deadline column — and it places findings with **no** due date last rather than dropping them from the page. - `--sla` and `--sort due_at` require `limacharlie` 5.6.2 or later. On - an older CLI, pass `sla=` and `sort=due_at` on the - [REST route](api-reference.md#reads) directly. - ## Bounds | Bound | Value | diff --git a/docs/email-security/ai-triage.md b/docs/email-security/ai-triage.md index 3c16a28f9..b33fe952a 100644 --- a/docs/email-security/ai-triage.md +++ b/docs/email-security/ai-triage.md @@ -373,21 +373,12 @@ Prove the recipe before trusting it. or report-resolution shows up in the message and report timelines and in the `EMAIL_ACTION` audit trail. -!!! warning "The agent needs the `mailsec` CLI in its runtime — the one real gap today" - The agent reaches Email Security by driving the `limacharlie mailsec ...` command - group, and that command group must be present in the CLI inside the session runtime. - The `lc-essentials` plugin installs the `limacharlie` CLI - ([runner environment](../9-ai-sessions/runner-environment.md)), but some runtimes still - ship a CLI old enough to predate the `mailsec` commands — a runtime on `v5.6.2`, for - example, lacks them. - - When that happens the agent still starts and still investigates through the events and - data it is handed, but it cannot run the `mailsec` tools to pivot or act — the - reference playbook detects the missing command group, reports the coverage gap, and - defers to a human rather than guessing. Confirm your session runtime carries a - `limacharlie` CLI new enough to include `limacharlie mailsec`. The server side — - verdict write-back, actions, report resolution, and the `submit_to_triage` trigger — - is live; this is purely about the CLI shipped in the agent's runtime. +!!! note "CLI tools in the agent runtime" + The agent uses `limacharlie mailsec ...` to investigate and act on messages. + The `lc-essentials` plugin installs the CLI in the + [session runtime](../9-ai-sessions/runner-environment.md). Confirm the runtime + installation with `limacharlie mailsec --help`; upgrade with + `python -m pip install --upgrade limacharlie` when needed. ## Passive first, then active diff --git a/docs/email-security/mcp.md b/docs/email-security/mcp.md index 2f6571b76..f3da7a67a 100644 --- a/docs/email-security/mcp.md +++ b/docs/email-security/mcp.md @@ -4,11 +4,10 @@ The [LimaCharlie MCP server](https://github.com/refractionPOINT/lc-mcp-server) lets an AI assistant review MailSec coverage, messages, campaigns and action -history. Start with a read-only session and one pilot mailbox. New MailSec tools -require a server build containing the `email_security` profiles; installed and -hosted versions may not include them yet. Check your client's tool list before -using the examples below. A newer client cannot enable an unavailable backend -feature or grant product access. +history. Start with a read-only session and one pilot mailbox. Select the +`email_security_readonly` profile for your first review and inspect the client's +tool list after connecting. Product access and backend capabilities are +configured separately from the client. ## Connect a read-only session diff --git a/docs/email-security/messages.md b/docs/email-security/messages.md index 5b647255e..712a5f798 100644 --- a/docs/email-security/messages.md +++ b/docs/email-security/messages.md @@ -57,13 +57,10 @@ limacharlie mailsec message list --verdict suspicious --verdict malicious \ --mailbox cfo@corp.example --since "$(date -d '7 days ago' +%s)" --oid $OID ``` -To inspect historical analysis separately, a development CLI with `--lane` -supports `mailsec message list --lane backfill`. For an older build, the stable -CLI's API command can send the same filter: +To inspect historical analysis separately: ```bash -limacharlie api "/v1/mailsec/$OID/messages" \ - --raw-field lane=backfill --field limit=10 --output yaml +limacharlie mailsec message list --lane backfill --limit 10 --oid "$OID" --output yaml ``` Historical messages are scored but do not trigger live-mail telemetry or diff --git a/docs/email-security/policy.md b/docs/email-security/policy.md index 9495fcac8..0b1d399b3 100644 --- a/docs/email-security/policy.md +++ b/docs/email-security/policy.md @@ -574,7 +574,7 @@ These are the trial terms. During beta, a deployment can report limits before enforcing them. Read `coverage.entitlement` for your actual standing and enforcement; a reported limit alone does not prove ingestion has paused. Contact LimaCharlie to confirm trial or scheduled-deletion enforcement in your data -region. Policy records and a development CLI cannot enable server enforcement. +region. Policy records and a CLI installation cannot enable server enforcement. ### The 14-day clock diff --git a/docs/email-security/setup-cli.md b/docs/email-security/setup-cli.md index 3a4d6de34..8cdcbf01d 100644 --- a/docs/email-security/setup-cli.md +++ b/docs/email-security/setup-cli.md @@ -104,7 +104,7 @@ always referenced, never inlined into the connection record. limacharlie mailsec onboarding --provider m365 --oid $OID ``` - Newer development builds can fill the Google commands in advance: + Fill the Google commands in advance with your project details: ```bash limacharlie mailsec onboarding --provider gworkspace \ @@ -114,9 +114,7 @@ always referenced, never inlined into the connection record. ``` Set the two variables to the project and service-account email from your - downloaded key. If `--help` does not list these flags, send `project_id`, - `sa_email`, `topic` and `subscription` to `GET /onboarding` through the - [API command](api-reference.md#reads), or update the development CLI. + downloaded key. The CLI uses these values to populate the onboarding instructions. ## 4. Connect the mail tenant diff --git a/docs/includes/code-security-cli-version.md b/docs/includes/code-security-cli-version.md index d6c034ce3..5279ae0eb 100644 --- a/docs/includes/code-security-cli-version.md +++ b/docs/includes/code-security-cli-version.md @@ -1,5 +1,4 @@ -!!! note "CLI examples use the development CLI" - Stable `limacharlie` 5.6.2 does not yet contain the Code Security commands - below. Follow [CLI installation](https://docs.limacharlie.io/cloud-security/code-security/getting-started/#cli-installation), or - use the console and documented REST routes. A newer CLI does not enable - features that are unavailable in your organization's data region. +!!! note "CLI setup" + Install or upgrade with `python -m pip install --upgrade limacharlie`. + See [CLI installation](https://docs.limacharlie.io/cloud-security/code-security/getting-started/#cli-installation) + for setup. Product access and server capabilities are configured separately. diff --git a/docs/includes/code-security-cli.md b/docs/includes/code-security-cli.md index 9dfa53b04..1225a5c1c 100644 --- a/docs/includes/code-security-cli.md +++ b/docs/includes/code-security-cli.md @@ -1,24 +1,12 @@ -!!! note "Code Security CLI availability" - The latest stable `limacharlie` release, **5.6.2**, includes Cloud Security - posture commands but does **not** include `cloudsec code`, `cloudsec image`, - Code Security evidence or remediation commands, or the `--repo` / `--source` finding - filters. Those CLI examples currently require the development version of - the [public Python SDK](https://github.com/refractionPOINT/python-limacharlie). - Install it separately from your normal CLI: +!!! note "Install the CLI" + Install or upgrade the LimaCharlie CLI: ```bash - python3 -m venv .venv-code-security - source .venv-code-security/bin/activate - python -m pip install --upgrade 'git+https://github.com/refractionPOINT/python-limacharlie.git@master' + python -m pip install --upgrade limacharlie limacharlie cloudsec code --help ``` - For repeatable scripts, replace `master` with a tested commit SHA and record - it with `python -m pip freeze`. Check the selected command's `--help` after - upgrading. You can also use the console or the documented REST routes with - the stable CLI's `limacharlie api` command. - - Installing a newer CLI does not enable a server capability. Hosted scanning + Installing the CLI does not enable a server capability. Hosted scanning and advanced evidence features depend on availability in your organization's data region. Check **Code security → Overview**, `code capabilities` and `code status`; if you see `code_lane_not_enabled_in_datacenter`, contact diff --git a/docs/includes/email-security-beta.md b/docs/includes/email-security-beta.md index 0242abdf3..4f77ac20b 100644 --- a/docs/includes/email-security-beta.md +++ b/docs/includes/email-security-beta.md @@ -5,20 +5,14 @@ While it is in beta, expect the surface described here to move: commands, fields and event shapes may change between releases, and they may change in - ways that are not backwards compatible. The MailSec CLI is currently available - from the Python SDK's **master branch**, ahead of a PyPI release. Install it - in a virtual environment before running the CLI examples: + ways that are not backwards compatible. Install or upgrade the CLI before + running the examples: ```bash - python3 -m venv .venv-mailsec - source .venv-mailsec/bin/activate - python -m pip install --upgrade 'git+https://github.com/refractionPOINT/python-limacharlie.git@master' + python -m pip install --upgrade limacharlie limacharlie mailsec --help ``` - Use that same installation for `hive` and `secret` commands. Credential-file - examples also require `jq`. For repeatable - scripts, replace `master` with the tested commit SHA; `python -m pip freeze` - records the installed revision. Re-read these pages after upgrading. + Credential-file examples also require `jq`. Re-read these pages after upgrading. Talk to us before relying on it in production. From 39f35d83a3fe828318aee86132cdda1d1c8503a2 Mon Sep 17 00:00:00 2001 From: Maxime Lamothe-Brassard Date: Wed, 30 Sep 2026 03:09:35 +0000 Subject: [PATCH 5/5] Remove repeated CLI version notices from Code Security pages --- docs/cloud-security/code-security/autofix.md | 2 -- docs/cloud-security/code-security/bring-your-own-scanner.md | 2 -- docs/cloud-security/code-security/code-rules.md | 2 -- docs/cloud-security/code-security/containment-setup.md | 2 -- docs/cloud-security/code-security/incident-response.md | 2 -- docs/cloud-security/code-security/index.md | 2 -- docs/cloud-security/code-security/policy.md | 2 -- docs/cloud-security/code-security/pull-requests.md | 2 -- docs/cloud-security/code-security/reference.md | 2 -- docs/cloud-security/code-security/results.md | 2 -- docs/cloud-security/code-security/troubleshooting.md | 2 -- docs/includes/code-security-cli-version.md | 4 ---- 12 files changed, 26 deletions(-) delete mode 100644 docs/includes/code-security-cli-version.md diff --git a/docs/cloud-security/code-security/autofix.md b/docs/cloud-security/code-security/autofix.md index a8c5d1f43..72465c589 100644 --- a/docs/cloud-security/code-security/autofix.md +++ b/docs/cloud-security/code-security/autofix.md @@ -1,7 +1,5 @@ # AutoFix pull requests ---8<-- "includes/code-security-cli-version.md" - For a vulnerable dependency with a published fixed version, Code Security can open the GitHub pull request that upgrades it. You review and merge it like any other pull request. diff --git a/docs/cloud-security/code-security/bring-your-own-scanner.md b/docs/cloud-security/code-security/bring-your-own-scanner.md index b995b702d..ad3953105 100644 --- a/docs/cloud-security/code-security/bring-your-own-scanner.md +++ b/docs/cloud-security/code-security/bring-your-own-scanner.md @@ -1,7 +1,5 @@ # Bring your own scanner ---8<-- "includes/code-security-cli-version.md" - You don't have to rely only on the hosted scan. You can: - **push results from a scanner you already run**, as SARIF or CycloneDX; diff --git a/docs/cloud-security/code-security/code-rules.md b/docs/cloud-security/code-security/code-rules.md index e33d88674..18dcae2af 100644 --- a/docs/cloud-security/code-security/code-rules.md +++ b/docs/cloud-security/code-security/code-rules.md @@ -1,7 +1,5 @@ # Code rules ---8<-- "includes/code-security-cli-version.md" - Static analysis runs **exactly your organization's enabled code rules** — nothing else. They are records in the `cloudsec_code_rule` Hive, and LimaCharlie's rules are records there too: there is no hidden built-in pack and no separate override diff --git a/docs/cloud-security/code-security/containment-setup.md b/docs/cloud-security/code-security/containment-setup.md index 7bfbf2048..049803987 100644 --- a/docs/cloud-security/code-security/containment-setup.md +++ b/docs/cloud-security/code-security/containment-setup.md @@ -1,7 +1,5 @@ # Configure evidence, lineage and remediation ---8<-- "includes/code-security-cli-version.md" - This page covers the settings behind the evidence chain, image lineage, live pull-request impact, runtime checks and remediation runs. It lists the permissions each one needs, what to grant on each connection, and which diff --git a/docs/cloud-security/code-security/incident-response.md b/docs/cloud-security/code-security/incident-response.md index 1783f880b..2006866a1 100644 --- a/docs/cloud-security/code-security/incident-response.md +++ b/docs/cloud-security/code-security/incident-response.md @@ -1,7 +1,5 @@ # Automatic behavior and incident response ---8<-- "includes/code-security-cli-version.md" - This page describes what Code Security does on its own when something goes wrong, what it never does on its own, and what you can do during an incident that involves a remediation. diff --git a/docs/cloud-security/code-security/index.md b/docs/cloud-security/code-security/index.md index 97426dac4..8e5f69e3c 100644 --- a/docs/cloud-security/code-security/index.md +++ b/docs/cloud-security/code-security/index.md @@ -1,7 +1,5 @@ # Code Security ---8<-- "includes/code-security-cli-version.md" - Code Security scans the source repositories behind your cloud estate and puts what it finds into the same risk-ranked worklist as your cloud findings. You triage a leaked credential or a vulnerable dependency the same way you triage a diff --git a/docs/cloud-security/code-security/policy.md b/docs/cloud-security/code-security/policy.md index a68a721e5..5a202df48 100644 --- a/docs/cloud-security/code-security/policy.md +++ b/docs/cloud-security/code-security/policy.md @@ -1,7 +1,5 @@ # Scan policy ---8<-- "includes/code-security-cli-version.md" - A `code_scanning` policy decides which repositories are scanned, which engines run, how often, and what happens on pull requests. With no enabled policy, nothing is scanned. diff --git a/docs/cloud-security/code-security/pull-requests.md b/docs/cloud-security/code-security/pull-requests.md index 92d196295..cf8d66311 100644 --- a/docs/cloud-security/code-security/pull-requests.md +++ b/docs/cloud-security/code-security/pull-requests.md @@ -1,7 +1,5 @@ # Pull-request checks and push rescans ---8<-- "includes/code-security-cli-version.md" - A scheduled scan tells you what a repository contains. On GitHub, Code Security can also: diff --git a/docs/cloud-security/code-security/reference.md b/docs/cloud-security/code-security/reference.md index fd80edf09..93c8a49d4 100644 --- a/docs/cloud-security/code-security/reference.md +++ b/docs/cloud-security/code-security/reference.md @@ -1,7 +1,5 @@ # Code Security reference ---8<-- "includes/code-security-cli-version.md" - ## Supported languages and ecosystems ### Dependencies (SCA) diff --git a/docs/cloud-security/code-security/results.md b/docs/cloud-security/code-security/results.md index f453d2f26..60a277dfa 100644 --- a/docs/cloud-security/code-security/results.md +++ b/docs/cloud-security/code-security/results.md @@ -1,7 +1,5 @@ # Working with results ---8<-- "includes/code-security-cli-version.md" - Code findings are ordinary [Cloud Security findings](../findings.md). They share the worklist, the triage actions (mitigated, accepted, false positive), owners, tickets, [remediation SLAs](../remediation-sla.md) and the `cloud_finding.*` diff --git a/docs/cloud-security/code-security/troubleshooting.md b/docs/cloud-security/code-security/troubleshooting.md index de5e19d6a..597d721ea 100644 --- a/docs/cloud-security/code-security/troubleshooting.md +++ b/docs/cloud-security/code-security/troubleshooting.md @@ -1,7 +1,5 @@ # Troubleshooting Code Security ---8<-- "includes/code-security-cli-version.md" - For evidence-chain, lineage, runtime-check and remediation reason codes, see [Unknown, partial and refusal reasons](reasons.md). diff --git a/docs/includes/code-security-cli-version.md b/docs/includes/code-security-cli-version.md deleted file mode 100644 index 5279ae0eb..000000000 --- a/docs/includes/code-security-cli-version.md +++ /dev/null @@ -1,4 +0,0 @@ -!!! note "CLI setup" - Install or upgrade with `python -m pip install --upgrade limacharlie`. - See [CLI installation](https://docs.limacharlie.io/cloud-security/code-security/getting-started/#cli-installation) - for setup. Product access and server capabilities are configured separately.