Metadata-Version: 2.5
Name: apisec-code-bolt
Version: 0.1.10
Summary: Static analysis probe for extracting architectural metadata from codebases
Project-URL: Homepage, https://apisec.ai
Project-URL: Documentation, https://docs.apisec.ai/code-bolt
Project-URL: Repository, https://github.com/apisec-inc/apisec-code-bolt
Author-email: APIsec <engineering@apisec.ai>
License: Proprietary
Keywords: api,security,static-analysis,vulnerability
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: click>=8.1.0
Requires-Dist: httpx>=0.26.0
Requires-Dist: javalang>=0.13.0
Requires-Dist: libcst>=1.1.0
Requires-Dist: networkx>=3.2
Requires-Dist: packaging>=23.0
Requires-Dist: pathspec>=0.12.0
Requires-Dist: pydantic-settings>=2.1.0
Requires-Dist: pydantic>=2.5.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.7.0
Requires-Dist: tree-sitter-c-sharp>=0.23
Requires-Dist: tree-sitter-java>=0.23
Requires-Dist: tree-sitter-javascript>=0.23
Requires-Dist: tree-sitter-python>=0.23
Requires-Dist: tree-sitter-ruby>=0.23
Requires-Dist: tree-sitter-typescript>=0.23
Requires-Dist: tree-sitter>=0.23
Requires-Dist: typing-extensions>=4.9.0
Provides-Extra: dev
Requires-Dist: mypy>=1.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: semgrep
Requires-Dist: semgrep>=1.50.0; extra == 'semgrep'
Description-Content-Type: text/markdown

# apisec-code-bolt

Static analysis probe for extracting architectural metadata from codebases.

## Overview

apisec-code-bolt analyzes source code to extract:

- **Routes/Endpoints** — HTTP routes, parameters, request/response types
- **Data Flows** — How data moves from entry points to sinks
- **Authentication** — Auth schemes, dependencies, role requirements
- **Integrations** — External services, databases, APIs
- **Dependencies** — Package dependencies and versions

The output is a structured **manifest** that can be uploaded to the APIsec cloud
for vulnerability analysis. **Raw source code never leaves your environment.**

## Requirements

- **Python 3.11 or newer** (3.11 and 3.12 are supported). Check with `python --version`.
- No JDK, Node, Ruby, or .NET runtime required — all parsers are pure-Python
  (Java via `javalang`, C#/JS/TS/Ruby via tree-sitter grammars). You can analyze
  a Java or Ruby project without those toolchains installed.

## Installation

The CLI is published on PyPI as [`apisec-code-bolt`](https://pypi.org/project/apisec-code-bolt/).

### Recommended: isolated install (pipx or uv)

Installing a CLI into an isolated environment avoids dependency conflicts with
other tools and sidesteps system-Python issues:

```bash
# Using pipx
pipx install apisec-code-bolt

# Or using uv (also handles the Python version for you)
uv tool install apisec-code-bolt
```

### Plain pip

```bash
pip install apisec-code-bolt
```

> **On an older or mismatched Python?** If `pip install` fails with a
> `requires-python` error, your default `python` is older than 3.11. The
> simplest fix is [`uv`](https://docs.astral.sh/uv/), which fetches a
> compatible interpreter automatically:
>
> ```bash
> uv tool install apisec-code-bolt          # install the CLI, or
> uv run --python 3.12 apisec-code-bolt ...  # run ad hoc under 3.12
> ```

### Verify the install

```bash
apisec-code-bolt --version
```

## Getting Started (end to end)

A full run is three steps: **register → authenticate → analyze**.

### 1. Register (first run only)

The first time you run the CLI it asks for the **registration code** APIsec
provided during onboarding (format `###-###`):

```bash
apisec-code-bolt analyze .    # prompts: "Please enter code (###-###)"
```

For non-interactive environments (CI, scripts), supply it via the environment
instead of typing it at a prompt:

```bash
export APISEC_REGISTRATION_CODE=123-456
```

### 2. Authenticate

Store your APIsec API key so uploads are authorized:

```bash
# Interactive (prompts for the key)
apisec-code-bolt auth

# Or pass the key directly
apisec-code-bolt auth sk_live_abc123...

# Confirm you're authenticated
apisec-code-bolt auth --check
```

### 3. Analyze

```bash
# Analyze the current project and upload the manifest to the cloud
apisec-code-bolt analyze .
```

On a successful upload the CLI prints a **"View Results in APIsec"** panel with a
direct link to your results in the console.

### Working offline / inspecting the manifest

```bash
# Analyze and save the manifest locally, no upload
apisec-code-bolt analyze . --output manifest.json --no-upload

# Analyze but write nothing — just print a summary (great for a first look)
apisec-code-bolt analyze . --dry-run

# Emit manifest JSON to stdout for piping into other tools
apisec-code-bolt analyze . --stdout --no-upload | jq .

# Give the extractor framework hints
apisec-code-bolt analyze . --frameworks fastapi,sqlalchemy
```

## Supported Languages & Frameworks

| Language | Frameworks |
|----------|-----------|
| Python | FastAPI, Flask, Django, GraphQL (Strawberry / Graphene / Ariadne), Celery, Click, Prefect |
| Java | Spring Boot, Micronaut, JAX-RS (Quarkus), GraphQL (Spring for GraphQL / graphql-java-kickstart) |
| JavaScript / TypeScript | Express, Fastify, NestJS, GraphQL (NestJS GraphQL / TypeGraphQL) |
| Ruby | Rails, Grape, Sinatra, GraphQL (graphql-ruby) |
| C# / .NET | ASP.NET Core, legacy ASP.NET (MVC/Web API), WCF, gRPC, Refit |

Framework coverage is validated end-to-end against real-world repositories in
the benchmark suite (`benchmark/`).

## Configuration

Scaffold a config file with sensible defaults:

```bash
apisec-code-bolt init            # writes .surface.yaml
```

`.surface.yaml` in your project root is picked up automatically:

```yaml
analysis:
  file_discovery:
    exclude_patterns:
      - "tests/**"
      - "**/migrations/**"
    max_files: 10000
    detect_workspace_boundaries: true  # see "Monorepo support" below

  data_flow:
    mode: inter_procedural
    max_depth: 10

cloud:
  enabled: true
  api_url: https://api.apisec.ai

output:
  format: json
```

## Monorepo support

When a scanned tree contains multiple independently-deployed sub-projects
(a pnpm/npm workspace, a Maven or Gradle multi-module build, a `.sln` with
several `.csproj`s, a `go.work`, or a uv/Poetry workspace — or, absent any of
those, any directory with its own recognised dependency manifest file),
`analyze` automatically detects each one as a separate boundary and uploads
its own manifest as its own Application, instead of one flat manifest mixing
every sub-project's routes, dependencies, and secrets together.

- **Activation is automatic and safe by default.** Detection only takes
  effect when **2 or more** real boundaries are found; a single-project repo
  is completely unaffected — same manifest, same canonical id, same
  `state.yaml`. Disable it entirely with `--no-detect-monorepo` or
  `detect_workspace_boundaries: false`.
- **Identity.** Each sub-project uploads under
  `{repo_canonical_id}/{relative/path/to/sub-project}`; code that doesn't
  belong to any detected sub-project (root-level config, CI files, a shared
  library with no manifest of its own) uploads under
  `{repo_canonical_id}/shared`.
- **Display name.** Each sub-project's Application is named
  `{repo_name}/{relative/path/to/sub-project}` (and `{repo_name}/shared` for
  the catch-all), so sibling services are distinguishable in the APIsec
  console's Applications list instead of all showing up under the identical
  bare repo name. A single-project repo is unaffected — same bare `repo_name`
  as always.
- **Auth-middleware scoping rides on the same gate — and this one is
  security-material.** A globally-registered auth middleware is attributed
  only to routes inside its own boundary, so one service's middleware can no
  longer mark a sibling service's routes as authenticated (which hides
  genuinely-exposed endpoints). Because it is gated on the same "2 or more
  boundaries" condition, a polyglot repo that presents only a **single**
  boundary — e.g. one root manifest and no per-service marker file or
  workspace config — falls back to the legacy path and gets repo-wide
  attribution. If a repo mixes languages or services, give each one its own
  dependency manifest (or declare a workspace) so boundary detection can see
  them; otherwise auth attribution is repo-wide and may over-report routes as
  protected.
  Scoping covers every auth path that resolves by *name* rather than by file:
  Spring Security filter chains, Rails `before_action` (including
  `ApplicationController`-inherited callbacks), Django view classes and
  decorators, and route-level auth dependencies — so two services that each
  define, say, an `articles` controller no longer share each other's guards.
- **Known v1 limitations:**
  - A response/request schema referenced by routes in more than one
    sub-project is duplicated into each of them; only one level of nested
    model references is followed.
  - The `shared` partition does not get the LLM-based surface-enrichment
    pass (it has no single directory to scope that scan to).
  - A cross-partition reference (e.g. a route depending on an auth guard
    defined in another sub-project) is preserved as-is and surfaced as a
    warning in that partition's manifest, not silently dropped or rewritten.

## Commands

Global options (before the subcommand): `--version`, `-v/--verbose`,
`-q/--quiet`, `--debug`, `--log-format [text|json]`.

### analyze

Analyze a codebase and generate/upload a manifest.

```bash
apisec-code-bolt analyze [PATH] [OPTIONS]

Options:
  -o, --output FILE     Save manifest to file instead of uploading
  --no-upload           Skip uploading to cloud (implies --output if not set)
  --api-key TEXT        Override stored API key
  --api-url TEXT        Applicationsservice base URL (all analysis traffic is proxied here)
  --format [json|yaml]  Output format
  --config FILE         Path to configuration file
  --frameworks TEXT     Comma-separated framework hints
  --exclude TEXT        Glob patterns to exclude (repeatable)
  --max-files INTEGER   Maximum files to analyze
  --timeout INTEGER     Analysis timeout in seconds
  --dry-run             Analyze and print a summary; write/upload nothing
  --stdout              Write manifest JSON to stdout (for pipelines)
  --detect-monorepo / --no-detect-monorepo
                        Detect monorepo sub-project boundaries and upload one
                        Application per sub-project (default: on; see
                        "Monorepo support" below)
```

### auth

Authenticate with the APIsec cloud.

```bash
apisec-code-bolt auth [API_KEY] [OPTIONS]

Options:
  --api-url TEXT  APIsec API URL
  --check         Check if already authenticated
  --logout        Remove stored credentials
```

### init

Scaffold a `.surface.yaml` configuration file.

```bash
apisec-code-bolt init [OPTIONS]

Options:
  -o, --output FILE  Output file path (default: .surface.yaml)
  --force            Overwrite an existing file
```

### validate

Validate a manifest file against the schema.

```bash
apisec-code-bolt validate MANIFEST_FILE
```

### answer

Answer verification queries (for air-gapped environments where the manifest was
uploaded separately and the cloud generated questions).

```bash
apisec-code-bolt answer [OPTIONS]

Options:
  -q, --questions FILE  Input questions file (JSON) [required]
  -o, --output FILE     Output answers file
  -r, --repo DIRECTORY  Repository path
  --timeout INTEGER     Query timeout in seconds
```

### telemetry

Manage anonymous usage telemetry (opt-out; on by default, disable any time with
`telemetry off`; never includes code, paths, or credentials).

```bash
apisec-code-bolt telemetry on|off|status
```

## Architecture

```
apisec-code-bolt/
├── cli/                 # Command-line interface
├── core/                # Types, config, manifest schema
├── parsing/             # Language-specific parsers
│   ├── python/          # LibCST-based Python parser
│   └── jvm/             # Java via the pure-Python javalang library
├── frameworks/          # Framework plugins
│   ├── python/          # FastAPI, Flask, Django, GraphQL, Celery, Click, Prefect
│   ├── java/            # Spring Boot, Micronaut, JAX-RS, GraphQL
│   ├── js/              # Express, Fastify, NestJS, GraphQL
│   ├── ruby/            # Rails, Grape, Sinatra, GraphQL
│   └── dotnet/          # ASP.NET Core, legacy ASP.NET, WCF, gRPC, Refit
├── analysis/            # Call graph, data flow
├── fingerprinting/      # Integration detection
├── query/               # Query API executor
└── cloud/               # Cloud communication
```

## Development

### Setup

```bash
# Clone and install in development mode
git clone https://github.com/apisec-inc/apisec-code-bolt.git
cd apisec-code-bolt
pip install -e ".[dev]"
```

### Running Tests

```bash
pytest
```

### Type Checking

```bash
mypy src/apisec_code_bolt
```

### Linting & Formatting

```bash
ruff check .
ruff format --check .
```

### Publishing a release (maintainers)

The CLI is published to [PyPI](https://pypi.org/project/apisec-code-bolt/) by the
**Publish to PyPI** GitHub Action. **Merging to `build` does NOT publish** — the
workflow only runs on `workflow_dispatch` or a published GitHub Release, and it
builds from whatever ref it runs on.

Prerequisites (one-time): the `PYPI_API_TOKEN` repository secret must be set
(Settings → Secrets and variables → Actions).

1. **Bump the version.** Edit `version` in `pyproject.toml` (single source of
   truth; `--version` reads it via package metadata). PyPI **rejects re-uploads**
   of an existing version, so the number must be higher than the current PyPI
   release. Open a PR and merge it to `build`.

2. **Publish** — dispatch the workflow (the standard path we use):
   Actions → *Publish to PyPI* → **Run workflow** → select branch **`build`**.

   ```bash
   gh workflow run "Publish to PyPI" --ref build
   ```

   <details><summary>Alternative: publish via a GitHub Release</summary>

   New release → create tag `vX.Y.Z` → set **Target: `build`** (it defaults to
   the default branch; only `build` has the bumped version) → Publish. This
   fires the same workflow via `release: [published]`.

   ```bash
   gh release create vX.Y.Z --target build --title "vX.Y.Z" --notes "…"
   ```
   </details>

3. **Verify.** Confirm the new version appears on
   [PyPI](https://pypi.org/project/apisec-code-bolt/), then upgrade an install:
   ```bash
   uv tool upgrade apisec-code-bolt   # or: pipx upgrade apisec-code-bolt
   ```

> Always release from `build` after the version bump has merged there — releasing
> from a ref that still carries the old version will fail the PyPI upload.

## Privacy

apisec-code-bolt is designed with privacy as a core principle:

- **No raw code egress** — Source code never leaves your environment
- **Metadata only** — The manifest contains structural information, not code
- **Outbound only** — Only makes outbound HTTPS calls to upload manifests
- **Air-gapped support** — Can run completely offline with file-based workflow

## License

Proprietary. Copyright © APIsec.

