security-scan
v0.1.10Report-only security reviews of operator-configured repositories at immutable Git commits, dispatched through a read-only Harness policy.
- macOS: arm64
- Linux: arm64 · armv7 · x64
- Windows: arm64 · x64
exact versions are immutable; binary and bundle artifacts are digest-pinned.
full markdown
/workers/security-scan.md?version=0.1.10. paste it into an llm prompt or pipe it through curl from a worker.install
configuration
- analysis:
max_cost_usd: 2
max_output_tokens: 8000
max_total_tokens: 50000
max_turns: 4
model:
repositories:
dependencies
readme
security-scan
security-scan accepts manual and operator-scheduled review requests for configured repositories and queues a report-only security analysis of an exact Git commit. It creates an isolated checkout of the full tree at that commit, constrains Harness to read-only code functions, validates the structured result, and never applies a suggested change. The SHA is not a commit-diff review and not a scan of git history. Omit target_sha (or leave the Console SHA field blank) to analyze the entire repository at HEAD.
Install
iii trigger compose::add worker=security-scanAnalysis requires the Harness stack. GitHub issue and draft fix-PR actions also require approval-gate to be live; those mutations stay closed until a user approves each one.
iii trigger compose::add worker=harness worker=approval-gateThe worker composes existing iii infrastructure rather than implementing local substitutes: private compare-and-set records live in state, durable steps run through queue, exact checkouts come from worktree, configured schedules bind through the cron dependency, analysis runs through harness, and GitHub publication is held by approval-gate.
Quickstart
Request a scan using a configured repository id and a full commit SHA:
iii trigger security-scan::request \
repository=iii-hq/iii \
target_sha="$(git -C /srv/repos/iii rev-parse HEAD)" \
mode=scan \
model=deepseek::deepseek-v4-flashThe request returns immediately:
{
"run_id": "sec_...",
"status": "queued",
"deduplicated": false
}Submitting the same repository, commit, mode, and model again returns the same run id with deduplicated: true. Omit target_sha to resolve HEAD and analyze the entire repository. Omit model to use the operator analysis.model (and its provider). A Console scan from the sidebar runs on the model picked in its analysis-model control; that picker defaults to following the composer catalog id of the open chat, such as deepseek::deepseek-v4-flash. A retryable failed run is restarted as a new attempt under that same id. If the first queue wake fails, the durable queued checkpoint remains available to the recovery sweep. Use mode=suggest to include minimal patch suggestions in the report; suggestions remain text and are never applied.
Read the current status or completed report:
iii trigger security-scan::read run_id=sec_...Read the persisted GitHub reconciliation snapshot, or explicitly refresh it:
iii trigger security-scan::reconciliation run_id=sec_...
iii trigger security-scan::reconciliation run_id=sec_... refresh=true limit=50The Harness count and GitHub alert counts answer different questions and are never added together. Harness findings are validated against the requested exact commit. Dependabot is a repository default-branch snapshot, while code scanning is a repository snapshot whose latest instances may refer to commits other than the requested SHA. A Harness count of 3 and GitHub source counts totaling 221 therefore remain 3 exact-commit findings and 221 GitHub records, not 224 unique findings.
Each GitHub source reports its own scope and collection status: complete, partial, unavailable, authentication_required, permission_denied, disabled, not_configured, or not_collected. complete with record_count: 0 is a successful empty collection. A null count means no usable count was collected and is not equivalent to zero. Records are deduplicated only by GitHub source and alert number; v1 does not claim semantic matches between model-authored Harness findings and typed GitHub alerts.
The default refresh=false reads the last sanitized snapshot without calling GitHub. Before the first collection it returns not_collected, or not_configured when no GitHub mapping exists. refresh=true queries Dependabot and code scanning, replaces the persisted snapshot, and then applies source, severity, lifecycle, cursor, and limit filters. One unavailable source does not fail the whole response; its status explains the missing count.
List recent runs, optionally filtered by repository or status:
iii trigger security-scan::list repository=iii-hq/iii status=completed limit=50Console page
When security-scan and Console are connected, open #/ext/security-scan to browse persisted run history and inspect a selected report. The page shows the exact repository and commit, current pipeline status, evidence and remediation for each finding, and suggested patches in suggest mode. Suggested patches remain read-only until you explicitly create a draft fix PR and approve the GitHub mutation. The sidebar form reviews the full tree at the pasted SHA. Its analysis-model picker lists the live router catalog and pins one model for the scan; left on follow chat it takes the model selected in the open chat composer, and falls back to the operator analysis.model when that chat has none. The catalog is re-read on the router's router::models::changed fan-out, so a credential added or a provider removed updates the list without a reload.
Each Harness finding can start an approval-gated GitHub issue. Completed suggest findings that include a patch can also start an isolated draft fix PR. GitHub reconciliation alerts are a separate snapshot and cannot start exact-commit Harness actions.
Run updates arrive through the security-scan:runs stream. The stream is a refresh doorbell rather than the source of truth: each frame makes the page refetch security-scan::list and security-scan::read. Nothing is polled. The page re-reads on three other events instead — the socket reconnecting, the tab becoming visible, and the refresh control — so a dropped frame delays convergence until the next event rather than stranding the view.
A completed report records coverage separately for vulnerabilities, dependencies, secrets, and supply-chain review. An area can be assessed, not assessed with a reason, or unknown for reports created before coverage tracking. Zero findings are never presented as proof that the code is vulnerability-free.
GitHub reconciliation and GitHub source links require the explicit operator-verified github.full_name mapping. The worker never infers a GitHub repository from the security-scan repository id.
For local UI development:
pnpm --dir security-scan/ui build
III_SECURITY_SCAN_UI_WATCH=security-scan/ui/dist cargo run --manifest-path security-scan/Cargo.tomlThe page header's standard settings control opens this worker in the Console's global Settings modal: the analysis budgets (max_turns and the token and cost ceilings), the operator analysis.model, and the repository allowlist all live there.
Configuration
Repositories are an operator-owned allowlist. Callers choose an id, not an arbitrary filesystem path or URL.
repositories:
- id: iii-hq/iii # stable id accepted by security-scan::request
path: /srv/repos/iii # local Git repository owned by the operator
github: # optional; required for GitHub reconciliation
full_name: iii-hq/iii # exact owner/name for this checkout
schedule: # optional; omit to disable automation for this repository
expression: "0 0 3 * * *" # second minute hour day month weekday [year], UTC
target_ref: refs/heads/main # resolved locally when each fire occurs
mode: scan # scan or suggest
analysis:
model: provider/model-id # required model from the live router catalog
provider: provider-id # optional explicit provider
max_turns: 4 # maximum Harness generations
max_output_tokens: 8000 # ceiling for one generation
max_total_tokens: 50000 # ceiling for the complete review
max_cost_usd: 2.0 # optional spend ceiling
archive: # optional; JSON copies of run records in `storage`
bucket: security-scan # worker-facing bucket name
prefix: runs # object key prefix, default runs/The shipped configuration leaves analysis.model empty and repositories: [] unchanged. Set a model and at least one repository before requesting a scan; the empty repository allowlist rejects every request.
github.full_name is optional so existing local-only repositories remain valid, but it must be configured explicitly as owner/name before refresh is enabled for that repository. The github worker needs an authenticated GitHub CLI session or GH_TOKEN with permission to read Dependabot and code-scanning alerts for the mapped repository. Authentication, permission, and disabled-feature failures are stored only as sanitized source statuses; credentials and raw dependency payloads are never persisted or returned.
Each repository has at most one schedule, so the repository id is also its unique schedule identity. The expression must use six fields starting with seconds, with an optional seventh year field. Cron evaluation is UTC. Fires missed while cron or security-scan is stopped are skipped and are not replayed.
At fire time the internal handler uses trigger metadata only to find this operator-owned configuration. It resolves target_ref with a bounded local git rev-parse call, does not fetch, requires one lowercase full 40-character commit SHA, and submits that SHA through the same security-scan::request path used manually. Repeated fires that resolve to the same repository, commit, and mode therefore return the existing run instead of creating duplicate work.
Configuration is loaded at worker startup in this MVP. Restart security-scan after changing repositories, GitHub mappings, schedules, analysis settings, or archive settings. The worker manifest starts github and cron as dependencies. If a manually assembled stack starts security-scan before a cron trigger owner is available, manual scans remain available and the recovery loop binds each configured schedule once cron appears.
Persistence
The Console Scan runs list is served from state. Point that worker at a file-backed or Redis adapter so history survives engine restarts. store_method: in_memory drops every run on shutdown.
Optional JSON copies of each run record are written through storage::putObject when archive.bucket is set. On boot, missing runs are imported from that bucket into state using storage::getObject and runs/manifest.json (storage does not list objects). Configure the bucket on the storage worker first:
providers:
local:
data_dir: ./data/storage
buckets:
security-scan:
provider: local
bucket: security-scanThe local provider spawns a rustfs sidecar (iii trigger compose::add worker=storage). Set $RUSTFS_BIN or put rustfs on PATH. JSON copies are a backup; the Console Scan runs list still comes from state.
Safety boundary
The worker accepts only 40-character commit SHAs, verifies the materialized checkout matches the requested commit, and disables ignored-file provisioning for scanner worktrees so local .env, dependency, and cache files are not copied into the review scope. The Harness scan turn can discover function contracts and call only coder::info, coder::tree, coder::list-folder, coder::read-file, and coder::search. It cannot run repository code, access the network, mutate files, update state, or start another agent.
Dependency sessions use private random identities rather than the public run id. Structured output is rejected if it exposes the internal checkout root or high-confidence credential material. Terminal scanner worktrees are removed through the existing worktree worker.
GitHub issue and draft fix-PR actions use a separate Harness session after an explicit user request. Issue sessions may call only github::issue::create. Fix sessions use an exact-SHA worktree with scoped file writes, explicit git commands, and github::pr::create. Both require approval::gate to be live; GitHub publication, branch push, and PR creation stay held until the user approves them. Fix PRs open as drafts and never merge automatically.
The public MVP exposes security-scan::request, security-scan::read, security-scan::list, security-scan::reconciliation, security-scan::action, and security-scan::action-read. security-scan::execute, security-scan::action-execute, security-scan::on-turn-completed, and security-scan::on-schedule are internal worker functions. Scan analysis still does not apply, commit, push, comment, review, merge, or dismiss alerts on its own.
This first phase is the bounded investigation layer. A later phase will feed it deterministic, pinned SAST, dependency, and secret-scanner candidates before Harness analysis, following the same candidate-discovery then evidence-review split used by DeepSec.
api reference (json)
{
"functions": [
{
"description": "Start an approval-gated GitHub issue or draft fix PR for one validated Harness finding. Duplicate run, finding, and action requests return the same action id.",
"metadata": {},
"name": "security-scan::action",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"SecurityActionKindV1": {
"enum": [
"issue",
"fix_pr"
],
"type": "string"
}
},
"properties": {
"action": {
"$ref": "#/definitions/SecurityActionKindV1"
},
"finding_index": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"run_id": {
"type": "string"
}
},
"required": [
"action",
"finding_index",
"run_id"
],
"title": "SecurityScanActionRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"SecurityActionKindV1": {
"enum": [
"issue",
"fix_pr"
],
"type": "string"
},
"SecurityActionStatusV1": {
"enum": [
"queued",
"preparing",
"awaiting_approval",
"completed",
"failed",
"cancelled"
],
"type": "string"
}
},
"properties": {
"action": {
"$ref": "#/definitions/SecurityActionKindV1"
},
"action_id": {
"type": "string"
},
"deduplicated": {
"type": "boolean"
},
"finding_index": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"run_id": {
"type": "string"
},
"status": {
"$ref": "#/definitions/SecurityActionStatusV1"
}
},
"required": [
"action",
"action_id",
"deduplicated",
"finding_index",
"run_id",
"status"
],
"title": "SecurityScanActionResponseV1",
"type": "object"
}
},
{
"description": "Commit the current fix action through its checkout-bound capability.",
"metadata": {
"internal": true
},
"name": "security-scan::action-commit",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action_id": {
"type": "string"
},
"capability": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"action_id",
"capability",
"message"
],
"title": "ActionCommitRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"commit_sha": {
"type": "string"
}
},
"required": [
"commit_sha"
],
"title": "ActionCommitResponseV1",
"type": "object"
}
},
{
"description": "Internal durable queue step for approval-gated GitHub issue and draft PR publication.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "security-scan::action-execute",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action_id": {
"type": "string"
},
"attempt": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"run_id": {
"type": "string"
},
"step": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"action_id",
"attempt",
"run_id",
"step"
],
"title": "ActionEnqueueRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"SecurityActionStatusV1": {
"enum": [
"queued",
"preparing",
"awaiting_approval",
"completed",
"failed",
"cancelled"
],
"type": "string"
}
},
"properties": {
"skipped": {
"type": "boolean"
},
"status": {
"$ref": "#/definitions/SecurityActionStatusV1"
},
"step": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"skipped",
"status",
"step"
],
"title": "ActionExecuteResponseV1",
"type": "object"
}
},
{
"description": "Push the current fix action through its checkout-bound capability.",
"metadata": {
"internal": true
},
"name": "security-scan::action-push",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action_id": {
"type": "string"
},
"capability": {
"type": "string"
}
},
"required": [
"action_id",
"capability"
],
"title": "ActionPushRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"branch": {
"type": "string"
}
},
"required": [
"branch"
],
"title": "ActionPushResponseV1",
"type": "object"
}
},
{
"description": "Read a durable security-scan GitHub action without exposing internal checkout paths or Harness session identifiers.",
"metadata": {},
"name": "security-scan::action-read",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"action_id": {
"type": "string"
}
},
"required": [
"action_id"
],
"title": "SecurityScanActionReadRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"PublicActionV1": {
"additionalProperties": false,
"properties": {
"action": {
"$ref": "#/definitions/SecurityActionKindV1"
},
"action_id": {
"type": "string"
},
"attempt": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"completed_at": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"created_at": {
"format": "int64",
"type": "integer"
},
"error": {
"anyOf": [
{
"$ref": "#/definitions/RunErrorV1"
},
{
"type": "null"
}
]
},
"finding_index": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"repository": {
"type": "string"
},
"result": {
"anyOf": [
{
"$ref": "#/definitions/SecurityActionResultV1"
},
{
"type": "null"
}
]
},
"run_id": {
"type": "string"
},
"schema_version": {
"type": "string"
},
"status": {
"$ref": "#/definitions/SecurityActionStatusV1"
},
"target_sha": {
"type": "string"
},
"updated_at": {
"format": "int64",
"type": "integer"
}
},
"required": [
"action",
"action_id",
"attempt",
"created_at",
"finding_index",
"repository",
"run_id",
"schema_version",
"status",
"target_sha",
"updated_at"
],
"type": "object"
},
"RunErrorV1": {
"additionalProperties": false,
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"retryable": {
"type": "boolean"
}
},
"required": [
"code",
"message",
"retryable"
],
"type": "object"
},
"SecurityActionKindV1": {
"enum": [
"issue",
"fix_pr"
],
"type": "string"
},
"SecurityActionResultV1": {
"additionalProperties": false,
"properties": {
"branch": {
"type": [
"string",
"null"
]
},
"commit_sha": {
"type": [
"string",
"null"
]
},
"draft": {
"type": [
"boolean",
"null"
]
},
"kind": {
"type": "string"
},
"url": {
"type": "string"
},
"validation": {
"type": [
"string",
"null"
]
}
},
"required": [
"kind",
"url"
],
"type": "object"
},
"SecurityActionStatusV1": {
"enum": [
"queued",
"preparing",
"awaiting_approval",
"completed",
"failed",
"cancelled"
],
"type": "string"
}
},
"properties": {
"action": {
"anyOf": [
{
"$ref": "#/definitions/PublicActionV1"
},
{
"type": "null"
}
]
}
},
"title": "SecurityScanActionReadResponseV1",
"type": "object"
}
},
{
"description": "Make a run's Harness review discoverable through session metadata and report whether it is available, without returning the private session identifier.",
"metadata": {},
"name": "security-scan::analysis-chat",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"run_id": {
"type": "string"
}
},
"required": [
"run_id"
],
"title": "SecurityScanAnalysisChatRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"available": {
"type": "boolean"
}
},
"required": [
"available"
],
"title": "SecurityScanAnalysisChatResponseV1",
"type": "object"
}
},
{
"description": "Stop an in-flight security-scan run. Queued and materializing runs are marked cancelled; analyzing runs stop the Harness turn and clean up the isolated checkout.",
"metadata": {},
"name": "security-scan::cancel",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"run_id": {
"type": "string"
}
},
"required": [
"run_id"
],
"title": "SecurityScanCancelRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
}
},
"properties": {
"deduplicated": {
"type": "boolean"
},
"run_id": {
"type": "string"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
}
},
"required": [
"deduplicated",
"run_id",
"status"
],
"title": "SecurityScanCancelResponseV1",
"type": "object"
}
},
{
"description": "Internal durable queue step for target materialization and read-only Harness dispatch.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "security-scan::execute",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"attempt": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"repository": {
"type": "string"
},
"run_id": {
"type": "string"
},
"step": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"attempt",
"repository",
"run_id",
"step"
],
"title": "EnqueueRequest",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
}
},
"properties": {
"skipped": {
"type": "boolean"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
},
"step": {
"format": "uint64",
"minimum": 0,
"type": "integer"
}
},
"required": [
"skipped",
"status",
"step"
],
"title": "ExecuteResponseV1",
"type": "object"
}
},
{
"description": "List security-scan runs as sanitized lightweight summaries, newest update first. Optional repository and status filters are applied before the bounded result limit.",
"metadata": {},
"name": "security-scan::list",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
}
},
"properties": {
"limit": {
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"repository": {
"type": [
"string",
"null"
]
},
"status": {
"anyOf": [
{
"$ref": "#/definitions/RunStatusV1"
},
{
"type": "null"
}
]
}
},
"title": "SecurityScanListRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"PublicRunSummaryV1": {
"additionalProperties": false,
"properties": {
"attempt": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"completed_at": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"created_at": {
"format": "int64",
"type": "integer"
},
"error": {
"anyOf": [
{
"$ref": "#/definitions/RunErrorV1"
},
{
"type": "null"
}
]
},
"finding_count": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"mode": {
"$ref": "#/definitions/ScanModeV1"
},
"model": {
"type": [
"string",
"null"
]
},
"repository": {
"type": "string"
},
"resolved_from_head": {
"type": "boolean"
},
"run_id": {
"type": "string"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
},
"target_sha": {
"type": "string"
},
"updated_at": {
"format": "int64",
"type": "integer"
}
},
"required": [
"attempt",
"created_at",
"finding_count",
"mode",
"repository",
"run_id",
"status",
"target_sha",
"updated_at"
],
"type": "object"
},
"RunErrorV1": {
"additionalProperties": false,
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"retryable": {
"type": "boolean"
}
},
"required": [
"code",
"message",
"retryable"
],
"type": "object"
},
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
},
"ScanModeV1": {
"enum": [
"scan",
"suggest"
],
"type": "string"
}
},
"properties": {
"runs": {
"items": {
"$ref": "#/definitions/PublicRunSummaryV1"
},
"type": "array"
}
},
"required": [
"runs"
],
"title": "SecurityScanListResponseV1",
"type": "object"
}
},
{
"description": "Internal UTC cron target that uses invocation metadata only to look up an operator-configured repository schedule, resolves its local Git ref at fire time, and queues the exact commit through security-scan::request.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "security-scan::on-schedule",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Payload emitted by the iii cron trigger. Values are observability data only; scan inputs come from operator configuration.",
"properties": {
"actual_time": {
"type": "string"
},
"job_id": {
"type": "string"
},
"scheduled_time": {
"type": "string"
},
"trigger": {
"type": "string"
}
},
"required": [
"actual_time",
"job_id",
"scheduled_time",
"trigger"
],
"title": "SecurityScanScheduleEventV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
},
"ScanModeV1": {
"enum": [
"scan",
"suggest"
],
"type": "string"
}
},
"properties": {
"deduplicated": {
"type": "boolean"
},
"mode": {
"$ref": "#/definitions/ScanModeV1"
},
"repository": {
"type": "string"
},
"run_id": {
"type": "string"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
},
"target_sha": {
"type": "string"
}
},
"required": [
"deduplicated",
"mode",
"repository",
"run_id",
"status",
"target_sha"
],
"title": "SecurityScanScheduleResponseV1",
"type": "object"
}
},
{
"description": "Internal Harness completion doorbell that validates and checkpoints a structured report.",
"metadata": {
"internal": true,
"trace_hidden": true
},
"name": "security-scan::on-turn-completed",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"reason": {
"default": null,
"type": [
"string",
"null"
]
},
"result": {
"default": null
},
"result_error": {
"default": null,
"type": [
"string",
"null"
]
},
"session_id": {
"default": "",
"type": "string"
},
"status": {
"default": "",
"type": "string"
},
"terminal": {
"default": false,
"type": "boolean"
},
"turn_id": {
"default": "",
"type": "string"
}
},
"title": "TurnCompletedEventV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
}
},
"properties": {
"status": {
"anyOf": [
{
"$ref": "#/definitions/RunStatusV1"
},
{
"type": "null"
}
]
},
"woke": {
"type": "boolean"
}
},
"required": [
"woke"
],
"title": "TurnCompletedResponseV1",
"type": "object"
}
},
{
"description": "Read a security-scan run and its validated report without exposing internal checkout paths or Harness session identifiers.",
"metadata": {},
"name": "security-scan::read",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"run_id": {
"type": "string"
}
},
"required": [
"run_id"
],
"title": "SecurityScanReadRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"AssessmentStatusV1": {
"enum": [
"assessed",
"not_assessed",
"unknown"
],
"type": "string"
},
"FindingLocationV1": {
"additionalProperties": false,
"properties": {
"line_end": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"line_start": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"path": {
"type": "string"
}
},
"required": [
"path"
],
"type": "object"
},
"PublicRunV1": {
"additionalProperties": false,
"properties": {
"attempt": {
"format": "uint32",
"minimum": 0,
"type": "integer"
},
"completed_at": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"created_at": {
"format": "int64",
"type": "integer"
},
"error": {
"anyOf": [
{
"$ref": "#/definitions/RunErrorV1"
},
{
"type": "null"
}
]
},
"mode": {
"$ref": "#/definitions/ScanModeV1"
},
"model": {
"type": [
"string",
"null"
]
},
"report": {
"anyOf": [
{
"$ref": "#/definitions/SecurityReportV1"
},
{
"type": "null"
}
]
},
"repository": {
"type": "string"
},
"resolved_from_head": {
"type": "boolean"
},
"run_id": {
"type": "string"
},
"schema_version": {
"type": "string"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
},
"target_sha": {
"type": "string"
},
"updated_at": {
"format": "int64",
"type": "integer"
}
},
"required": [
"attempt",
"created_at",
"mode",
"repository",
"run_id",
"schema_version",
"status",
"target_sha",
"updated_at"
],
"type": "object"
},
"RunErrorV1": {
"additionalProperties": false,
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"retryable": {
"type": "boolean"
}
},
"required": [
"code",
"message",
"retryable"
],
"type": "object"
},
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
},
"ScanModeV1": {
"enum": [
"scan",
"suggest"
],
"type": "string"
},
"SecurityAreaAssessmentV1": {
"additionalProperties": false,
"properties": {
"reason": {
"type": [
"string",
"null"
]
},
"status": {
"$ref": "#/definitions/AssessmentStatusV1"
}
},
"required": [
"status"
],
"type": "object"
},
"SecurityAssessmentsV1": {
"additionalProperties": false,
"properties": {
"dependencies": {
"$ref": "#/definitions/SecurityAreaAssessmentV1"
},
"secrets": {
"$ref": "#/definitions/SecurityAreaAssessmentV1"
},
"supply_chain": {
"$ref": "#/definitions/SecurityAreaAssessmentV1"
},
"vulnerabilities": {
"$ref": "#/definitions/SecurityAreaAssessmentV1"
}
},
"required": [
"dependencies",
"secrets",
"supply_chain",
"vulnerabilities"
],
"type": "object"
},
"SecurityFindingV1": {
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"evidence": {
"type": "string"
},
"location": {
"anyOf": [
{
"$ref": "#/definitions/FindingLocationV1"
},
{
"type": "null"
}
]
},
"remediation": {
"type": "string"
},
"rule_id": {
"type": "string"
},
"severity": {
"$ref": "#/definitions/SeverityV1"
},
"suggested_patch": {
"type": [
"string",
"null"
]
},
"title": {
"type": "string"
}
},
"required": [
"description",
"evidence",
"remediation",
"rule_id",
"severity",
"title"
],
"type": "object"
},
"SecurityReportV1": {
"additionalProperties": false,
"properties": {
"assessments": {
"$ref": "#/definitions/SecurityAssessmentsV1"
},
"findings": {
"items": {
"$ref": "#/definitions/SecurityFindingV1"
},
"type": "array"
},
"summary": {
"type": "string"
}
},
"required": [
"assessments",
"findings",
"summary"
],
"type": "object"
},
"SeverityV1": {
"enum": [
"critical",
"high",
"medium",
"low",
"info"
],
"type": "string"
}
},
"properties": {
"run": {
"anyOf": [
{
"$ref": "#/definitions/PublicRunV1"
},
{
"type": "null"
}
]
}
},
"title": "SecurityScanReadResponseV1",
"type": "object"
}
},
{
"description": "Read or refresh a persisted, sanitized comparison of one Harness report with separately counted Dependabot and code-scanning snapshots. Supports bounded source, severity, lifecycle, and cursor filters; never reports a combined unique total.",
"metadata": {},
"name": "security-scan::reconciliation",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"ReconciliationLifecycleV1": {
"enum": [
"open"
],
"type": "string"
},
"ReconciliationSourceV1": {
"enum": [
"dependabot",
"code_scanning"
],
"type": "string"
},
"SeverityV1": {
"enum": [
"critical",
"high",
"medium",
"low",
"info"
],
"type": "string"
}
},
"properties": {
"cursor": {
"type": [
"string",
"null"
]
},
"lifecycle": {
"anyOf": [
{
"$ref": "#/definitions/ReconciliationLifecycleV1"
},
{
"type": "null"
}
]
},
"limit": {
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"refresh": {
"default": false,
"type": "boolean"
},
"run_id": {
"type": "string"
},
"severity": {
"anyOf": [
{
"$ref": "#/definitions/SeverityV1"
},
{
"type": "null"
}
]
},
"source": {
"anyOf": [
{
"$ref": "#/definitions/ReconciliationSourceV1"
},
{
"type": "null"
}
]
}
},
"required": [
"run_id"
],
"title": "SecurityScanReconciliationRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"HarnessReconciliationStatusV1": {
"enum": [
"verified",
"not_available"
],
"type": "string"
},
"HarnessReconciliationSummaryV1": {
"additionalProperties": false,
"properties": {
"scope": {
"$ref": "#/definitions/ReconciliationScopeV1"
},
"status": {
"$ref": "#/definitions/HarnessReconciliationStatusV1"
},
"verified_at": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"verified_count": {
"description": "Validated Harness report findings. This is never added to GitHub source counts.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
}
},
"required": [
"scope",
"status"
],
"type": "object"
},
"ReconciliationAlertV1": {
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"end_line": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"lifecycle": {
"$ref": "#/definitions/ReconciliationLifecycleV1"
},
"number": {
"format": "uint64",
"minimum": 0,
"type": "integer"
},
"observed_at": {
"type": [
"string",
"null"
]
},
"path": {
"type": [
"string",
"null"
]
},
"public_url": {
"description": "Reconstructed public github.com URL. Dependency-provided URLs are never persisted.",
"type": "string"
},
"scope": {
"$ref": "#/definitions/ReconciliationScopeV1"
},
"severity": {
"$ref": "#/definitions/SeverityV1"
},
"source": {
"$ref": "#/definitions/ReconciliationSourceV1"
},
"start_line": {
"format": "uint64",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"structured_ids": {
"default": [],
"description": "Exact source identifiers only, such as GHSA, CVE, or scanner rule IDs.",
"items": {
"type": "string"
},
"type": "array"
},
"title": {
"type": "string"
}
},
"required": [
"description",
"lifecycle",
"number",
"public_url",
"scope",
"severity",
"source",
"title"
],
"type": "object"
},
"ReconciliationHealthStatusV1": {
"enum": [
"healthy",
"warning",
"error",
"unknown"
],
"type": "string"
},
"ReconciliationLifecycleV1": {
"enum": [
"open"
],
"type": "string"
},
"ReconciliationMatchingStatusV1": {
"enum": [
"available",
"unavailable"
],
"type": "string"
},
"ReconciliationMatchingV1": {
"additionalProperties": false,
"properties": {
"matched_records": {
"description": "Present only when exact structured identifiers produced matches.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/ReconciliationMatchingStatusV1"
}
},
"required": [
"status"
],
"type": "object"
},
"ReconciliationScopeV1": {
"enum": [
"exact_commit",
"repository_default_branch",
"repository_snapshot"
],
"type": "string"
},
"ReconciliationSourceHealthV1": {
"additionalProperties": false,
"properties": {
"commit_sha": {
"type": [
"string",
"null"
]
},
"observed_at": {
"type": [
"string",
"null"
]
},
"status": {
"$ref": "#/definitions/ReconciliationHealthStatusV1"
},
"tool": {
"type": [
"string",
"null"
]
}
},
"required": [
"status"
],
"type": "object"
},
"ReconciliationSourceStatusV1": {
"enum": [
"complete",
"partial",
"unavailable",
"authentication_required",
"permission_denied",
"disabled",
"not_configured",
"not_collected"
],
"type": "string"
},
"ReconciliationSourceSummaryV1": {
"additionalProperties": false,
"properties": {
"collected_at": {
"description": "Collection time in Unix milliseconds. Null means the source was not queried.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"health": {
"$ref": "#/definitions/ReconciliationSourceHealthV1"
},
"record_count": {
"description": "Number of normalized records when collection returned usable data. Null is unavailable/not-collected and is deliberately distinct from zero.",
"format": "uint32",
"minimum": 0,
"type": [
"integer",
"null"
]
},
"scope": {
"$ref": "#/definitions/ReconciliationScopeV1"
},
"source": {
"$ref": "#/definitions/ReconciliationSourceV1"
},
"status": {
"$ref": "#/definitions/ReconciliationSourceStatusV1"
}
},
"required": [
"health",
"scope",
"source",
"status"
],
"type": "object"
},
"ReconciliationSourceV1": {
"enum": [
"dependabot",
"code_scanning"
],
"type": "string"
},
"SeverityV1": {
"enum": [
"critical",
"high",
"medium",
"low",
"info"
],
"type": "string"
}
},
"properties": {
"github_repository": {
"type": [
"string",
"null"
]
},
"harness": {
"$ref": "#/definitions/HarnessReconciliationSummaryV1"
},
"matching": {
"$ref": "#/definitions/ReconciliationMatchingV1"
},
"next_cursor": {
"type": [
"string",
"null"
]
},
"records": {
"items": {
"$ref": "#/definitions/ReconciliationAlertV1"
},
"type": "array"
},
"repository": {
"type": "string"
},
"run_id": {
"type": "string"
},
"schema_version": {
"type": "string"
},
"sources": {
"items": {
"$ref": "#/definitions/ReconciliationSourceSummaryV1"
},
"type": "array"
},
"target_sha": {
"type": "string"
}
},
"required": [
"harness",
"matching",
"records",
"repository",
"run_id",
"schema_version",
"sources",
"target_sha"
],
"title": "SecurityScanReconciliationResponseV1",
"type": "object"
}
},
{
"description": "Scan a repository for security issues, report-only, at one commit. Pass an exact 40-character target_sha, or omit it to review HEAD. Duplicate repository, commit, mode and model requests return the same run id.",
"metadata": {},
"name": "security-scan::request",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"ScanModeV1": {
"enum": [
"scan",
"suggest"
],
"type": "string"
}
},
"properties": {
"mode": {
"$ref": "#/definitions/ScanModeV1"
},
"model": {
"description": "Catalog model id from the Console composer. Omitted requests use operator `analysis.model`.",
"type": [
"string",
"null"
]
},
"provider": {
"description": "Optional explicit provider. Omitted when `model` is a catalog id such as `deepseek::…`.",
"type": [
"string",
"null"
]
},
"repository": {
"type": "string"
},
"target_sha": {
"default": "",
"description": "Exact 40-character commit SHA. Omit or leave empty to analyze the entire repository at HEAD.",
"type": "string"
}
},
"required": [
"mode",
"repository"
],
"title": "SecurityScanRequestV1",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"RunStatusV1": {
"enum": [
"queued",
"materializing",
"materialized",
"dispatching",
"analyzing",
"completed",
"failed",
"cancelling",
"cancelled"
],
"type": "string"
}
},
"properties": {
"deduplicated": {
"type": "boolean"
},
"run_id": {
"type": "string"
},
"status": {
"$ref": "#/definitions/RunStatusV1"
}
},
"required": [
"deduplicated",
"run_id",
"status"
],
"title": "SecurityScanResponseV1",
"type": "object"
}
},
{
"description": "Serve the security-scan worker's injected console UI assets (content function for its console:script / console:style triggers).",
"metadata": {
"internal": true
},
"name": "security-scan::ui-content",
"request_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Input of the content function: the console asks for one asset by path.",
"properties": {
"path": {
"description": "The asset path from the trigger config (e.g. `state/page.js`).",
"type": "string"
}
},
"required": [
"path"
],
"title": "UiContentInput",
"type": "object"
},
"response_schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "Output of the content function.",
"properties": {
"content": {
"description": "The asset source, verbatim.",
"type": "string"
},
"content_type": {
"description": "MIME type the console should serve the asset with.",
"type": "string"
}
},
"required": [
"content",
"content_type"
],
"title": "UiContentResult",
"type": "object"
}
}
],
"triggers": []
}