Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions apps/openant-cli/cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ func runAnalyze(cmd *cobra.Command, args []string) {
if analyzeAnalyzerOutput == "" {
analyzeAnalyzerOutput = ctx.scanFile("analyzer_output.json")
}
if analyzeAppContext == "" {
analyzeAppContext = ctx.scanFile("application_context.json")
}
if analyzeRepoPath == "" {
analyzeRepoPath = ctx.RepoPath
}
Expand Down
112 changes: 112 additions & 0 deletions apps/openant-cli/cmd/generatecontext.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package cmd

import (
"fmt"
"os"

"github.com/knostic/open-ant-cli/internal/output"
"github.com/knostic/open-ant-cli/internal/python"
"github.com/spf13/cobra"
)

var generateContextCmd = &cobra.Command{
Use: "generate-context [repository-path]",
Short: "Generate application security context for a repository",
Long: `Analyzes a repository and produces an application_context.json file
that describes the application type, trust boundaries, intended
behaviors, and patterns that should not be flagged as vulnerabilities.

This context is automatically used by the analyze and verify commands
to reduce false positives.

If no repository path is given, the active project is used (see: openant init).

The command checks for a manual override file (OPENANT.md or OPENANT.json)
in the repository root before falling back to LLM-based generation.
Use --force to skip the manual override check.`,
Args: cobra.MaximumNArgs(1),
Run: runGenerateContext,
}

var (
gcOutput string
gcForce bool
gcShowPrompt bool
)

func init() {
generateContextCmd.Flags().StringVarP(&gcOutput, "output", "o", "", "Output path (default: <scan-dir>/application_context.json or <repo>/application_context.json)")
generateContextCmd.Flags().BoolVar(&gcForce, "force", false, "Force regeneration, ignoring OPENANT.md override files")
generateContextCmd.Flags().BoolVar(&gcShowPrompt, "show-prompt", false, "Include formatted prompt text in output")
}

func runGenerateContext(cmd *cobra.Command, args []string) {
repoPath, ctx, err := resolveRepoArg(args)
if err != nil {
output.PrintError(err.Error())
os.Exit(2)
}

// Apply project defaults
if ctx != nil {
if gcOutput == "" {
gcOutput = ctx.scanFile("application_context.json")
}
}

rt, err := ensurePython()
if err != nil {
output.PrintError(err.Error())
os.Exit(2)
}

// Build Python CLI args
pyArgs := []string{"generate-context", repoPath}
if gcOutput != "" {
pyArgs = append(pyArgs, "--output", gcOutput)
}
if gcForce {
pyArgs = append(pyArgs, "--force")
}
if gcShowPrompt {
pyArgs = append(pyArgs, "--show-prompt")
}

result, err := python.Invoke(rt.Path, pyArgs, "", quiet, requireAPIKey())
if err != nil {
output.PrintError(err.Error())
os.Exit(2)
}

if jsonOutput {
output.PrintJSON(result.Envelope)
} else if result.Envelope.Status == "success" {
if data, ok := result.Envelope.Data.(map[string]any); ok {
printGenerateContextSummary(data)
}
} else {
output.PrintErrors(result.Envelope.Errors)
}

os.Exit(result.ExitCode)
}

func printGenerateContextSummary(data map[string]any) {
output.PrintHeader("Application Context Generated")
if v, ok := data["application_type"].(string); ok {
output.PrintKeyValue("Type", v)
}
if v, ok := data["purpose"].(string); ok {
output.PrintKeyValue("Purpose", v)
}
if v, ok := data["confidence"].(float64); ok {
output.PrintKeyValue("Confidence", fmt.Sprintf("%.0f%%", v*100))
}
if v, ok := data["source"].(string); ok {
output.PrintKeyValue("Source", v)
}
if v, ok := data["app_context_path"].(string); ok {
output.PrintKeyValue("Output", v)
}
fmt.Println()
}
22 changes: 12 additions & 10 deletions apps/openant-cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ Stage 1: Detect potential vulnerabilities via code analysis
Stage 2: Simulate an attacker to eliminate false positives

Commands:
scan Full pipeline: parse → enhance → detect → verify → report
diff Scan only code changed vs a base ref or GitHub PR
parse Extract code units from a repository
enhance Add security context to a parsed dataset
analyze Run Stage 1 vulnerability detection
verify Run Stage 2 attacker simulation
build-output Assemble pipeline_output.json from verified results
dynamic-test Docker-isolated exploit testing
report Generate reports from analysis results
config Manage CLI configuration (API key, etc.)`,
scan Full pipeline: parse → enhance → detect → verify → report
diff Scan only code changed vs a base ref or GitHub PR
parse Extract code units from a repository
generate-context Generate application security context
enhance Add security context to a parsed dataset
analyze Run Stage 1 vulnerability detection
verify Run Stage 2 attacker simulation
build-output Assemble pipeline_output.json from verified results
dynamic-test Docker-isolated exploit testing
report Generate reports from analysis results
config Manage CLI configuration (API key, etc.)`,
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down Expand Up @@ -82,6 +83,7 @@ func init() {
rootCmd.AddCommand(scanCmd)
rootCmd.AddCommand(diffCmd)
rootCmd.AddCommand(parseCmd)
rootCmd.AddCommand(generateContextCmd)
rootCmd.AddCommand(enhanceCmd)
rootCmd.AddCommand(analyzeCmd)
rootCmd.AddCommand(verifyCmd)
Expand Down
3 changes: 3 additions & 0 deletions apps/openant-cli/cmd/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ func runVerify(cmd *cobra.Command, args []string) {
if verifyAnalyzerOutput == "" {
verifyAnalyzerOutput = ctx.scanFile("analyzer_output.json")
}
if verifyAppContext == "" {
verifyAppContext = ctx.scanFile("application_context.json")
}
if verifyRepoPath == "" {
verifyRepoPath = ctx.RepoPath
}
Expand Down
12 changes: 8 additions & 4 deletions libs/openant-core/CURRENT_IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,17 @@ Unsupported types (desktop apps, mobile apps, games, embedded systems) are rejec

**Usage:**
```bash
# List supported types
python -m context.generate_context --list-types
# Generate context via CLI (recommended)
openant generate-context /path/to/repo

# Generate context for a repository
# Generate context via Python module
python -m context.generate_context /path/to/repo

# Context is saved to application_context.json in the dataset directory
# List supported types
python -m context.generate_context --list-types

# Context is saved to application_context.json in the scan/dataset directory
# analyze and verify auto-discover it when using a project
```

**Generated Context Structure:**
Expand Down
3 changes: 2 additions & 1 deletion libs/openant-core/DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ For AI assistants working on the code, here are the key source files:
| File | Purpose |
|------|---------|
| `context/application_context.py` | Context detection & formatting |
| `context/generate_context.py` | CLI for context generation |
| `context/generate_context.py` | Python module CLI for context generation |
| `openant/cli.py` (`generate-context`) | Primary CLI command (`openant generate-context`) |

### Report Generator

Expand Down
21 changes: 16 additions & 5 deletions libs/openant-core/PIPELINE_MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,15 +534,26 @@ For typical web applications, entry-point filtering achieves 60-95% reduction.

Classifies the repository type to reduce false positives.

**Location:** `context/generate_context.py`
**Location:** `context/application_context.py`, `openant/cli.py`

**Command:**
**Command (via CLI):**
```bash
openant generate-context # Uses active project
openant generate-context /path/to/repo # Explicit repo path
openant generate-context /path/to/repo -o ctx.json # Custom output path
openant generate-context --force # Skip OPENANT.md override
openant generate-context --show-prompt # Include prompt format in output
```

**Command (via Python module):**
```bash
python -m context.generate_context /path/to/repo
python -m context.generate_context /path/to/repo -o application_context.json
python -m context.generate_context --list-types # Show supported types
```

When using a project (`openant init`), the output defaults to the project scan directory and is automatically discovered by `analyze` and `verify` — no need to pass `--app-context`.

**Supported Application Types:**

| Type | Description | Attack Model |
Expand Down Expand Up @@ -885,7 +896,7 @@ python parsers/python/parse_repository.py /path/to/flask-app \
python validate_dataset_schema.py datasets/flask-app/dataset.json

# 3. Generate application context
python -m context.generate_context /path/to/flask-app
openant generate-context /path/to/flask-app

# 4. Run Stage 1 + Stage 2 on first 20 units
python experiment.py --dataset flask-app --verify --limit 20
Expand All @@ -907,7 +918,7 @@ python parsers/javascript/test_pipeline.py /path/to/node-app \
python validate_dataset_schema.py datasets/node-app/dataset.json

# 3. Generate application context
python -m context.generate_context /path/to/node-app
openant generate-context /path/to/node-app

# 4. Run full analysis
python experiment.py --dataset node-app --verify
Expand Down Expand Up @@ -953,7 +964,7 @@ python parsers/python/parse_repository.py /repo --output datasets/name/dataset.j
python parsers/javascript/test_pipeline.py /repo --analyzer-path /analyzer.js --output datasets/name --processing-level codeql

# Generate app context
python -m context.generate_context /repo
openant generate-context /repo

# Run Stage 1
python experiment.py --dataset name
Expand Down
16 changes: 9 additions & 7 deletions libs/openant-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,18 @@ OpenAnt generates application context to understand what type of application is
### Generate Context

```bash
# Generate context for a repository
python -m context.generate_context /path/to/repo

# View formatted prompt output
python -m context.generate_context /path/to/repo --show-prompt
# Generate context via CLI (recommended)
openant generate-context /path/to/repo
openant generate-context /path/to/repo --show-prompt # Include prompt format
openant generate-context --force # Skip OPENANT.md override

# List supported types
python -m context.generate_context --list-types
# Generate context via Python module
python -m context.generate_context /path/to/repo
python -m context.generate_context --list-types # Show supported types
```

When using a project (`openant init`), `analyze` and `verify` auto-discover the generated context — no need to pass `--app-context`.

### Manual Override

Create `OPENANT.md` or `OPENANT.json` in your repository root to provide manual security context. This is useful when:
Expand Down
Loading
Loading