Add Cloud Security (CNAPP) support: 'limacharlie cloudsec' CLI + SDK#310
Merged
Conversation
Wraps the full /cloudsec/{oid}/... gateway REST surface (35 routes) in
a new CloudSec SDK class and a 'cloudsec' command group:
- findings worklist: list/facets/get + triage writes (resolve incl.
reopen via kind=open, bulk-resolve, set-owner, set-ticket)
- attack paths, CIEM (public-access, facets)
- inventory (list/facets), DSPM data-security facets, resource point
lookup by urn
- security graph: 1-hop neighbors, query pack list, graph query run
(named/text/DSL)
- compliance: report (framework or scoped assignment), frameworks,
assignments
- overview, chokepoints (list/dismiss/restore), changes, risk-trend,
scan-status
- sensor <-> cloud asset resolution (bulk)
- CAASM: assets, coverage gaps, expected-coverage policy get/set,
raw record ingest
- provider credential preflight (POST providers/test)
Reads need cloudsec.get, writes cloudsec.set; all routes are behind
the ext-cloud-inventory subscription gate. Provider configs and the
cloudsec policies remain hive records (cloudsec_provider /
cloudsec_policy / cloudsec_query) managed via the existing hive
commands; the explain texts point there.
Repeatable query params (severity, finding_class, sid, urn, ...) are
sent as repeated keys via list-of-pairs query_params; write bodies are
JSON. Unit tests cover the SDK request shapes and the CLI arg parsing;
the lazy-loading regression snapshot gains the new group.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrqM5AzjBtH7F9hFN4aGjw
lcbill
previously approved these changes
Jul 10, 2026
…s, chunked resolve Fixes from the multi-agent review of this PR: - finding bulk-resolve: drop 'open' from the accepted kinds — the bulk API rejects it (reopen is single-finding only); help/explain updated - scan-status --provider and caasm ingest --source: no longer click.Choice — both are growing server-side registries (7 providers live today) validated server-side with clean errors - JSON `null` inputs no longer bypass shape validation: --records-file, --record-json, --query-json, --policy-json all get unconditional type checks; `query run --text ""` now fails client-side instead of round-tripping - resolve sensors/assets: chunk bulk batches (100 ids/request) so any batch size works — repeated query params previously hit the ~8KB LB URL limit near 190 ids while docstrings advertised 500 - file inputs (--input-file/--records-file) now accept YAML or JSON like every other command module, and policy set / provider test read piped stdin — replaces the bespoke JSON-only loader - Client: urlencode query_params with doseq=True (sequence values expand to repeated keys instead of a Python list repr) and widen the query_params type hints; regression test added - sdk/cloudsec: collapse the per-method query-pair boilerplate into a single _query_pairs builder - tests: per-subgroup help coverage for every cloudsec subgroup, plus the null-input, empty-text, bulk-open, YAML, stdin, and chunking cases Full unit suite: 3585 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JrqM5AzjBtH7F9hFN4aGjw
lcbill
previously approved these changes
Jul 10, 2026
…rs, shared loader
- get_scan_status lowercases the provider before sending: the backend
scan-state read is a case-sensitive lookup keyed on lowercase provider
ids, so a raw "AWS" silently read as never-scanned
- extract commands/_input_helpers.py (load_file/load_stdin/
parse_yaml_or_json) as the canonical YAML-or-JSON input loader with
clean BadParameter errors — cloudsec now imports it instead of
carrying the codebase's 7th private copy; malformed piped stdin gets
a usage error instead of a raw JSONDecodeError traceback
- _one_of: None means absent but an explicit empty string is rejected —
both alone (empty selector) and alongside a real option (ambiguous
invocation), restoring the strict exactly-one arbitration
- fix stale contract text the previous commit missed: resolve command
docstrings no longer claim "max 500", scan-status SDK docstring no
longer claims a closed gcp|aws|azure list, and the provider-test
explain text now shows the correct v2 hive syntax (--hive-name +
--input-file, not positional + --data)
- tests/unit/conftest.py: autouse guard that fails any unit test
reaching limacharlie.client.urlopen — local dev machines carry live
credentials, so an unmocked invocation that slips past argument
validation would otherwise hit a real org (this bit during
development: a YAML-tolerant parse of '{"a": }' let an unmocked test
make a live call)
Full unit suite: 3588 passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JrqM5AzjBtH7F9hFN4aGjw
lcbill
approved these changes
Jul 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds first-class CLI + SDK support for the new Cloud Security (CNAPP) product, wrapping the full
/cloudsec/{oid}/...gateway REST surface (35 routes, verified against the gateway route registrations and backend handlers).New SDK class —
limacharlie/sdk/cloudsec.py(CloudSec(org)), one method per route, returning the raw JSON response shapes.New command group —
limacharlie cloudsec ...:overview,changes,risk-trend,scan-statusfinding list/facets/get--severity/--class/--status/--account,--kev/--reachable,-q, sort + keyset pagination)finding resolve/bulk-resolve/set-owner/set-ticket--kind openreopens (clears the disposition, keeps owner/ticket)attack-path listciem public-access/facetsinventory list/facets,data-security facets,resource getgraph neighbors,query list/runcompliance report/frameworks/assignmentschokepoint list/dismiss/restoreresolve sensors/assetsprovider testhive://secret/<name>)Every command has
--ai-helpexplain text; the group help documents thecloudsec.get/cloudsec.setpermissions and theext-cloud-inventoryenable gate.Deliberately out of scope
cloudsec_provider,cloudsec_policy, andcloudsec_queryare hive records already fully manageable vialimacharlie hive ...; the explain texts point there instead of duplicating shortcuts.?format=csvon findings/inventory/query/compliance): the client's JSON parsing doesn't carry raw CSV bodies; the global--output csvcovers the need client-side.Testing
tests/unit/test_sdk_cloudsec.py: asserts the exact URL, repeated-key query pairs, and JSON body shape for every SDK method against a mocked client.tests/unit/test_cli_cloudsec.py: CliRunner coverage of arg parsing, repeatable filters, boolean tri-state flags, mutually-exclusive inputs, JSON/file inputs, and choice validation.🤖 Generated with Claude Code
https://claude.ai/code/session_01JrqM5AzjBtH7F9hFN4aGjw
Backend follow-ups surfaced by review (not fixable in this repo)
kind: open(clear disposition), the bulk RPC does not — so bulk reopen is impossible platform-wide. The CLI now blocksopenon bulk, but the capability gap belongs to the graph service's bulk handler.GET /resolve/*request, but the ~8KB LB URL limit caps a real request near ~190 ids — no client can reach the advertised cap. Either a POST-based bulk resolve route or a documented cap matching GET reality would remove the trap (this SDK chunks at 100 to stay safe).