codeanalyzer-iac
Beta
The codeanalyzer-iac backend analyzes infrastructure-as-code. Its command is caniac. It reads a repository, or a Neo4j graph that already holds one, and publishes one typed model of the infrastructure sources.
caniac is built on the Helm SDK, pinned to version 4.2.4. It never calls the helm CLI. Helm is the first dialect. Every other file stays an ordinary Artifact, and the backend never removes it.
Install
Section titled “Install”Prebuilt binary for macOS and Linux:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/codellm-devkit/codeanalyzer-iac/releases/latest/download/caniac-installer.sh | shbrew install codellm-devkit/tap/codeanalyzer-iacpip install codeanalyzer-iacAnalyze a repository
Section titled “Analyze a repository”caniac --app-name payments .caniac --app-name payments charts/ deploy/values-prod.yamlcaniac --app-name payments --workspace-root . charts/apiPaths can be files or directories, and they can overlap. They are selection filters, not identity roots. Identity comes from --workspace-root, which defaults to the current directory. charts/api/values.yaml is therefore the same artifact whether you selected the repository, charts/, or that one file.
Every input file and every --config file must resolve below the workspace root. The backend does not follow symlinks out of it, and the walker skips .git.
With no path, the input is .. With no --app-name, the application takes the base name of the workspace root. In graph mode a name is mandatory.
Analysis levels
Section titled “Analysis levels”| Level | Adds | Never does |
|---|---|---|
| L1 | Artifact classification, Helm facets, chart metadata, values keys, template definitions, template calls, value references, resource templates, source diagnostics | Resolution or rendering |
| L2 | Chart membership, dependency resolution, named-template targets, value-reference targets, unresolved records | Rendering or any I/O |
| L3 | Render profiles, value layers, renders, rendered Kubernetes resources and addresses | Cluster access, install, upgrade, dependency fetching |
-a/--analysis-level takes 1, 2, or 3, and defaults to 1. The levels are additive. Every fact that a lower level published is present, unchanged, at every higher level.
The graph always receives the deepest implemented level, which is L3 today. --emit cypher and --emit neo4j therefore raise the level to 3 unless you passed --analysis-level yourself. If you pass an explicit level below 3 with those targets, caniac rejects the run with an error. It does not silently raise the level.
caniac testdata/helm/l1-v2 --app-name payments --analysis-level 1 > analysis.json
caniac --workspace-root testdata/helm/profiles --app-name payments \ --config .codeanalyzer-iac.yaml --analysis-level 3 > analysis.jsonOutput modes
Section titled “Output modes”--emit | Writes | To stdout | To -o DIR |
|---|---|---|---|
json (filesystem default) | The analysis document | Compact JSON, one trailing newline | analysis.json |
cypher | The replayable projection script | The script | graph.cypher |
neo4j (graph-mode default) | A reconciled generation over Bolt | Nothing | Nothing |
schema | The embedded graph catalog | schema.neo4j.json | schema.neo4j.json |
In filesystem mode, --emit cypher never consults the target graph. The script is projected from the analysis alone, so it has no hash-conflict guard against facts that are already in the graph. --emit neo4j does have that guard. In filesystem mode, --emit neo4j needs the target database. Give it with --neo4j-uri <uri> or with the NEO4J_URI environment variable.
--emit schema takes no input path. -f/--format accepts only json. msgpack is named so that the backend can reject it with a clear message instead of a bad parse. -j/--jobs bounds parallel parsing and rendering, and it defaults to the CPU count. The output is byte-identical whatever you set it to.
Stdout carries analysis data and nothing else. Errors go to stderr, one line each. A successful run leaves stderr empty. The backend discards the value-coalescing warnings that Helm emits. They reach neither stream.
Graph mode
Section titled “Graph mode”A single positional Neo4j or Bolt URI switches caniac into graph mode.
caniac neo4j://localhost:7687 --app-name paymentsIn graph mode the backend reads the complete Artifact.source for every can://artifact/<app-name>/... node. It makes sure that each one matches the stored sha256. Then it writes its enrichment back onto those same nodes.
--app-name is required here. The URI names a database, not an application, and the backend does not select one for you. You cannot mix a URI and filesystem paths in one invocation. In graph mode --emit defaults to neo4j, so the command above reads and writes the same database over one connection. The connection reads --neo4j-user, --neo4j-password, and --neo4j-database, or the NEO4J_USERNAME, NEO4J_PASSWORD, and NEO4J_DATABASE environment variables. The user defaults to neo4j.
If a source does not match its recorded hash, that becomes a diagnostic on the artifact and the backend skips its semantic model. The recorded spans address the stored text, so a changed source makes every one of them wrong. The backend analyzes the other artifacts normally. There is no flag to accept a mismatch.
Exit status
Section titled “Exit status”| Exit | Meaning |
|---|---|
| 0 | The analysis completed |
| 1 | A run-wide failure, or --strict with at least one error-severity diagnostic |
Isolated failures are diagnostics inside the model, not process failures. An unparsable file, or a chart that the backend cannot render, still exits 0. A file that the backend cannot read as text stays a raw inventory entry, with a digest and no source. It reports IAC_SOURCE_NOT_TEXT at warning severity. A repository with binaries in it therefore still passes --strict.
A run that exits 1 publishes a document only when the failure comes after the write:
caniacreports an invalid configuration and a--strictfailure after it writes the analysis, so those runs leave a document to read.- An unreadable input root, an unreachable graph, and a failed graph commit all end the run before that write, so they publish nothing.
--strict changes only the exit status. It never changes the document.
--eager removes the stale facts that this backend owns for the selected application: codeanalyzer-iac nodes and aliases, iac_* properties, facet labels, and IAC_* relationships. It never removes an Artifact.
Schema
Section titled “Schema”The repository pins the accepted codeanalyzer-schema contract at commit b84428f. make schema-check and the pin-parity test keep every copy of that commit in step.