Spec: Expanded Security Scanning
Intent Description
The static-analysis-integration skill's Tier 1 baseline (semgrep, gitleaks, trivy, hadolint, actionlint) covers general polyglot SAST and CI hygiene but leaves three gaps: deep program-analysis dataflow (CodeQL), language-specific security linting (Bandit/Python, ESLint-security/JS+TS, SpotBugs+FSB/JVM), and offline-capable SCA (Grype). Trivy's existing invocation makes network calls that fail in restricted-egress environments.
This change adds nine tools in a capability-scoped, language-detected pipeline: each tool runs only when its target language or asset type is present, preventing false install requirements in polyglot repos. Gitleaks is updated to run with --no-verify (no outbound API calls to confirm active credentials). Trivy's network behavior is tightened to local-DB-only. Checkov fills the IaC gap more completely than trivy-config alone, running alongside it on Dockerfiles and covering Terraform, CloudFormation, and Kubernetes declarative configs.
All new tools normalize to the existing unified finding envelope v1.0 and extend the deduplication priority chain. The combined output remains a single findings array — the scanner count increases but the output contract does not change.
User-Facing Behavior
Feature: Expanded security scanning with language detection
Background:
Given the static-analysis-integration skill is invoked
# ── Gitleaks (updated) ─────────────────────────────────────────────────────
Scenario: Gitleaks runs with --no-verify flag
Given gitleaks is installed
When the skill runs
Then gitleaks detects --report-format sarif --report-path - --no-verify
And no outbound API calls are made to verify detected secrets
# ── CodeQL ────────────────────────────────────────────────────────────────
Scenario: CodeQL runs once per detected compiled language
Given the repository contains both Java and Kotlin source files
And CodeQL is installed
When the skill detects available tools
Then CodeQL creates one database per language using the appropriate build command
And analysis runs against the default query suite for each language in parallel
And findings from all language runs are merged and normalized to the unified finding envelope v1.0
Scenario: CodeQL is skipped when no compiled language files are present
Given the repository contains only JavaScript and Python files
When the skill runs
Then CodeQL is skipped silently with no entry in tools_missing
Scenario: CodeQL database build fails for one language
Given the repository contains Java and Kotlin source files
And the Kotlin build command exits non-zero
When the skill runs
Then CodeQL is skipped for Kotlin with a warning: "CodeQL database build failed — kotlin skipped"
And CodeQL continues for Java
And all other tools continue running
Scenario: CodeQL is not installed
Given CodeQL is not on PATH
And the repository contains Java source files
When the skill runs
Then CodeQL produces status: skip
And an install hint is included in tools_missing
# ── Bandit ────────────────────────────────────────────────────────────────
Scenario: Bandit runs when Python source files are present
Given the repository contains .py source files
And bandit is installed
When the skill runs
Then Bandit scans all Python files
And findings are normalized to the unified finding envelope v1.0
Scenario: Bandit is skipped when no Python files are present
Given the repository contains no .py files
When the skill runs
Then Bandit is skipped silently with no entry in tools_missing
Scenario: Bandit is not installed but Python files are present
Given the repository contains .py source files
And bandit is not installed
When the skill runs
Then an install hint for bandit appears in tools_missing
# ── ESLint + eslint-plugin-security ───────────────────────────────────────
Scenario: ESLint security plugin runs when JS or TS source files are present
Given the repository contains .js or .ts source files
And eslint is installed
And eslint-plugin-security is present in node_modules
When the skill runs
Then ESLint runs with the security plugin ruleset
And findings are normalized to the unified finding envelope v1.0
Scenario: ESLint security is skipped when no JS or TS files are present
Given the repository contains no .js or .ts files
When the skill runs
Then ESLint security is skipped silently with no entry in tools_missing
Scenario: eslint-plugin-security is missing even though eslint is installed
Given eslint is installed
But eslint-plugin-security is not present in node_modules
And the repository contains .ts source files
When the skill runs
Then an install hint for eslint-plugin-security appears in tools_missing
And ESLint is skipped for this invocation
Scenario: ESLint is not installed but JS/TS files are present
Given the repository contains .ts source files
And eslint is not installed
When the skill runs
Then an install hint for eslint + eslint-plugin-security appears in tools_missing
# ── SpotBugs + Find Security Bugs ─────────────────────────────────────────
Scenario: SpotBugs runs when compiled JVM bytecode is available
Given the repository contains Java or Kotlin source files
And a build has produced .class files or a JAR artifact
And SpotBugs with the FSB plugin is installed
When the skill runs
Then SpotBugs with FSB runs against the bytecode
And findings are normalized to the unified finding envelope v1.0
Scenario: SpotBugs triggers a build when no bytecode exists
Given the repository contains Java source files
And no compiled bytecode or JAR exists
And SpotBugs with the FSB plugin is installed
When the skill runs
Then the skill triggers the detected build tool (mvn or gradle)
And SpotBugs runs against the resulting bytecode
Scenario: SpotBugs is skipped when build fails
Given the repository contains Java source files
And no compiled bytecode exists
And the build command exits non-zero
When the skill runs
Then SpotBugs is skipped
And a warning is emitted: "SpotBugs skipped — build failed for JVM analysis"
Scenario: SpotBugs is not installed but JVM files are present
Given the repository contains .java source files
And spotbugs is not on PATH
When the skill runs
Then an install hint for SpotBugs + Find Security Bugs appears in tools_missing
# ── Checkov ───────────────────────────────────────────────────────────────
Scenario: Checkov scans IaC assets when present
Given the repository contains Terraform, CloudFormation, Kubernetes, or Dockerfile assets
And checkov is installed
When the skill runs
Then Checkov scans all detected IaC asset types
And findings are normalized to the unified finding envelope v1.0
Scenario: Checkov and trivy-config both scan Dockerfiles
Given the repository contains a Dockerfile
And both checkov and trivy are installed
When the skill runs
Then both Checkov and trivy-config scan the Dockerfile
And findings from both tools are merged and deduplicated before output
And trivy takes priority over checkov for duplicate findings
Scenario: Checkov is skipped when no IaC assets are present
Given the repository contains no Terraform, CloudFormation, Kubernetes, or Dockerfile files
When the skill runs
Then Checkov is skipped silently with no entry in tools_missing
Scenario: Checkov is not installed but IaC assets are present
Given the repository contains a Dockerfile
And checkov is not installed
When the skill runs
Then an install hint for checkov appears in tools_missing
# ── Trivy offline ─────────────────────────────────────────────────────────
Scenario: Trivy runs in offline mode when a local DB is present
Given trivy is installed
And a local vulnerability database exists at the expected cache path
When the skill runs
Then Trivy runs with --skip-update and --offline-scan flags
And no network calls are made during the scan
Scenario: Trivy warns and skips when local DB is absent
Given trivy is installed
But no local vulnerability database exists at the expected cache path
When the skill runs
Then Trivy is skipped
And a warning is emitted: "trivy local DB missing — run: trivy image --download-db-only"
Scenario: Trivy warns when local DB is stale
Given trivy is installed
And the local vulnerability database is more than 7 days old
When the skill runs
Then Trivy runs but emits a warning: "trivy DB is N days old — consider refreshing with: trivy image --download-db-only"
# ── Grype ─────────────────────────────────────────────────────────────────
Scenario: Grype runs against dependency manifests when present
Given the repository contains package.json, requirements.txt, pom.xml, or go.mod
And grype is installed with a locally synced vulnerability database
When the skill runs
Then Grype scans all detected dependency manifests
And findings are normalized to the unified finding envelope v1.0
And no network calls are made during the scan
Scenario: Grype warns and skips when local DB is absent
Given grype is installed
But grype db status shows the database is not present
When the skill runs
Then Grype is skipped
And a warning is emitted: "grype local DB missing — run: grype db update"
Scenario: Grype warns when local DB is stale
Given grype is installed
And the local vulnerability database is more than 7 days old
When the skill runs
Then Grype runs but emits a warning: "grype DB is N days old — consider refreshing with: grype db update"
Scenario: Grype is skipped when no dependency manifests are present
Given the repository contains no recognized dependency manifests
When the skill runs
Then Grype is skipped silently with no entry in tools_missing
# ── Deduplication ─────────────────────────────────────────────────────────
Scenario: Duplicate findings across tools are deduplicated by priority
Given both Semgrep and Bandit report a finding at the same file and line
When findings are normalized and deduplicated
Then only one finding appears in the output
And it is attributed to semgrep (higher priority)
Scenario: Extended priority chain is respected for CodeQL vs Semgrep
Given CodeQL and Semgrep both report a finding at the same file and line
When findings are deduplicated
Then the CodeQL finding is retained
And the Semgrep finding is discarded
# ── Output contract unchanged ─────────────────────────────────────────────
Scenario: All tool findings appear in a single normalized output
Given multiple new tools run successfully
When the skill completes
Then the output schema is unchanged from unified finding envelope v1.0
And a summary counts findings by tool and severity
And tools_missing lists each absent conditional tool with a capability label and install hint
Architecture Specification
Files to change
plugins/agentic-dev-team/skills/static-analysis-integration/SKILL.md — tool tiers, language detection gate, offline enforcement, deduplication chain
plugins/agentic-dev-team/skills/static-analysis-integration/references/tool-configs.md — per-tool invocation commands, adapter references, install hints
plugins/agentic-dev-team/skills/static-analysis-integration/adapters/ — three new bespoke adapters (≤ 40 LOC each)
New adapters
| File |
Tool |
Input |
Notes |
bandit-adapter.py |
Bandit |
Bandit JSON |
bandit -r <path> -f json |
eslint-security-adapter.py |
ESLint |
ESLint JSON |
eslint --format json |
spotbugs-adapter.py |
SpotBugs + FSB |
SpotBugs XML |
spotbugs -xml |
Tool tier placement
| Tool |
Tier |
SARIF? |
Condition |
| Gitleaks (updated) |
1 |
native |
always; add --no-verify |
| CodeQL |
2 |
native |
.java, .kt, .c, .cpp, .cs, .swift present |
| Bandit |
2 |
bespoke adapter |
.py present |
| ESLint + eslint-plugin-security |
2 (promoted from Tier 4) |
bespoke adapter |
.js/.ts present + plugin in node_modules |
| SpotBugs + FSB |
2 |
bespoke adapter |
.java/.kt present |
| Checkov |
2 |
native (--output sarif) |
Terraform/CFn/K8s/Dockerfile present |
| Trivy (updated) |
1 |
native |
always; enforce --skip-update --offline-scan |
| Grype |
2 |
native |
package.json/requirements.txt/pom.xml/go.mod present |
Language detection gate
Each conditional tool checks for target file types via find before dispatch. No tool runs if no matching files exist. Detection runs once per invocation and is shared across tools that overlap (e.g., Java detection covers both CodeQL and SpotBugs).
CodeQL per-language DB strategy
For each detected compiled language, codeql database create --language=<lang> --command=<build> runs independently. Multiple language runs execute in parallel. Build command defaults: mvn clean package -DskipTests (Maven), gradle build -x test (Gradle), dotnet build (C#). Unknown build systems surface a warning and skip that language.
SpotBugs build trigger
If .class files or JARs are absent, the skill detects the build tool (pom.xml → Maven, build.gradle → Gradle) and triggers a build. Build failure skips SpotBugs with a warning; it does not fail the pipeline.
ESLint detection
command -v eslint checks binary presence. Plugin presence is checked via node -e "require('eslint-plugin-security')" from the repo root. Both must pass or ESLint is skipped.
Offline DB enforcement (Trivy, Grype)
Pre-flight check before each run: confirm DB path exists and mtime < 7 days. DB absence → skip + warning. DB stale → run + warning. Neither is a hard pipeline failure.
Deduplication priority chain (extended)
semgrep > codeql > gitleaks > bandit > eslint-security > spotbugs > trivy > checkov > grype > hadolint > actionlint
No output schema changes. All tools normalize to unified finding envelope v1.0. tools_missing entries follow the existing install-hint format.
Acceptance Criteria
- Each conditional tool runs only when its target language or asset type is detected — verified by a test with a repo containing only non-matching files.
- All new tools produce findings conforming to unified finding envelope v1.0; schema violations fail the run with tool name + rule id.
- Missing tools produce install hints in the existing format; absent tools never cause pipeline failure.
- Gitleaks invocation includes
--no-verify; no outbound network calls are made during secret scanning.
- CodeQL creates one database per detected compiled language; a build failure for one language skips that language and continues others.
- SpotBugs triggers a build when bytecode is absent; build failure surfaces a warning and skips SpotBugs without failing the pipeline.
- ESLint security is skipped if
eslint-plugin-security is not in node_modules, even when eslint is installed.
- Trivy runs with
--skip-update --offline-scan; absence of local DB produces a warning containing "trivy local DB missing".
- Grype makes zero network calls during scan execution; absence of local DB produces a warning containing "grype local DB missing".
- Stale DB (>7 days) for Trivy or Grype produces a warning with day count but does not skip the tool.
- Checkov and trivy-config both run on Dockerfiles; duplicate findings are deduplicated with trivy taking priority.
- Deduplication respects the extended priority chain:
semgrep > codeql > gitleaks > bandit > eslint-security > spotbugs > trivy > checkov > grype > hadolint > actionlint.
- Three new bespoke adapters (Bandit, ESLint-security, SpotBugs) are each ≤ 40 LOC.
- All Tier 1 tool behavior (semgrep, trivy IaC, hadolint, actionlint) is unchanged except Gitleaks (
--no-verify) and Trivy (offline enforcement).
tools_missing lists conditional tools that are absent only when their target language/asset is present in the repo.
Consistency Gate
Spec: Expanded Security Scanning
Intent Description
The static-analysis-integration skill's Tier 1 baseline (semgrep, gitleaks, trivy, hadolint, actionlint) covers general polyglot SAST and CI hygiene but leaves three gaps: deep program-analysis dataflow (CodeQL), language-specific security linting (Bandit/Python, ESLint-security/JS+TS, SpotBugs+FSB/JVM), and offline-capable SCA (Grype). Trivy's existing invocation makes network calls that fail in restricted-egress environments.
This change adds nine tools in a capability-scoped, language-detected pipeline: each tool runs only when its target language or asset type is present, preventing false install requirements in polyglot repos. Gitleaks is updated to run with
--no-verify(no outbound API calls to confirm active credentials). Trivy's network behavior is tightened to local-DB-only. Checkov fills the IaC gap more completely than trivy-config alone, running alongside it on Dockerfiles and covering Terraform, CloudFormation, and Kubernetes declarative configs.All new tools normalize to the existing unified finding envelope v1.0 and extend the deduplication priority chain. The combined output remains a single findings array — the scanner count increases but the output contract does not change.
User-Facing Behavior
Architecture Specification
Files to change
plugins/agentic-dev-team/skills/static-analysis-integration/SKILL.md— tool tiers, language detection gate, offline enforcement, deduplication chainplugins/agentic-dev-team/skills/static-analysis-integration/references/tool-configs.md— per-tool invocation commands, adapter references, install hintsplugins/agentic-dev-team/skills/static-analysis-integration/adapters/— three new bespoke adapters (≤ 40 LOC each)New adapters
bandit-adapter.pybandit -r <path> -f jsoneslint-security-adapter.pyeslint --format jsonspotbugs-adapter.pyspotbugs -xmlTool tier placement
--no-verify.java,.kt,.c,.cpp,.cs,.swiftpresent.pypresent.js/.tspresent + plugin in node_modules.java/.ktpresent--output sarif)--skip-update --offline-scanpackage.json/requirements.txt/pom.xml/go.modpresentLanguage detection gate
Each conditional tool checks for target file types via
findbefore dispatch. No tool runs if no matching files exist. Detection runs once per invocation and is shared across tools that overlap (e.g., Java detection covers both CodeQL and SpotBugs).CodeQL per-language DB strategy
For each detected compiled language,
codeql database create --language=<lang> --command=<build>runs independently. Multiple language runs execute in parallel. Build command defaults:mvn clean package -DskipTests(Maven),gradle build -x test(Gradle),dotnet build(C#). Unknown build systems surface a warning and skip that language.SpotBugs build trigger
If
.classfiles or JARs are absent, the skill detects the build tool (pom.xml→ Maven,build.gradle→ Gradle) and triggers a build. Build failure skips SpotBugs with a warning; it does not fail the pipeline.ESLint detection
command -v eslintchecks binary presence. Plugin presence is checked vianode -e "require('eslint-plugin-security')"from the repo root. Both must pass or ESLint is skipped.Offline DB enforcement (Trivy, Grype)
Pre-flight check before each run: confirm DB path exists and
mtime < 7 days. DB absence → skip + warning. DB stale → run + warning. Neither is a hard pipeline failure.Deduplication priority chain (extended)
No output schema changes. All tools normalize to unified finding envelope v1.0.
tools_missingentries follow the existing install-hint format.Acceptance Criteria
--no-verify; no outbound network calls are made during secret scanning.eslint-plugin-securityis not innode_modules, even wheneslintis installed.--skip-update --offline-scan; absence of local DB produces a warning containing "trivy local DB missing".semgrep > codeql > gitleaks > bandit > eslint-security > spotbugs > trivy > checkov > grype > hadolint > actionlint.--no-verify) and Trivy (offline enforcement).tools_missinglists conditional tools that are absent only when their target language/asset is present in the repo.Consistency Gate