Documentation
¶
Overview ¶
Package mcp implements the MCP server mode: a thin, stateless adapter that exposes the same core sensors as MCP tools (PRD section 10). It reimplements no audit logic — every tool call translates to the same engine the CLI uses — and relies on prompt caching to neutralize the stateless overhead.
Status: BUILT. NewServer registers the tool set and Serve runs it over the stdio transport; every tool is a thin adapter onto a core handler. The HTTP/SSE transport is the one part still unbuilt — `mcp serve --port` returns an explicit error rather than falling back silently.
Index ¶
- Constants
- func NewServer() *mcpsdk.Server
- func Serve(ctx context.Context) error
- func SupportedLanguageNames() []string
- type ActionableSection
- type BaselineAcceptRequest
- type BaselineAcceptResponse
- type BaselineDelta
- type BaselineListRequest
- type BaselineListResponse
- type BaselinePruneRequest
- type BaselinePruneResponse
- type BaselineRegisterAuthzHelperRequest
- type BaselineRegisterAuthzHelperResponse
- type BaselineUnregisterAuthzHelperRequest
- type BaselineUnregisterAuthzHelperResponse
- type BudgetBlock
- type CheckCVEsRequest
- type CheckCVEsResponse
- type ConfirmSurfaceRequest
- type ConfirmSurfaceResponse
- type CoverageRequest
- type CoverageResponse
- type DBSection
- type FileInput
- type FrontierPending
- type GoneItem
- type ResolvedClean
- type ScanAllRequest
- type ScanAllResponse
- type ScanAllSummary
- type ScanDBRequest
- type ScanDBResponse
- type ScanEndpointRequest
- type ScanEndpointResponse
- type ScanRequest
- type ScanResponse
- type ScopeBlock
- type SecuritySection
- type SurfaceIDORRequest
- type SurfaceResponse
- type Tool
- type VulnerableDependency
Constants ¶
const ( ScopeModeFull = "full" ScopeModePartial = "partial" )
The two scan modes. A response ALWAYS carries one of them: the field's presence is not conditional, so a consumer never has to infer the mode from an absence.
const ResponseBudgetBytes = 40_000
ResponseBudgetBytes is the byte budget codefit-scan-all declares for its own serialized response.
What is MEASURED (roadmap P0-4): a bisection run against a real MCP client (Claude Code, 2026-08-09), driving the v0.2.6 binary over stdio with controlled-size responses cut from trimmed copies of a real 317-file project. The real ceiling was bracketed, not pinpointed:
64 097 bytes ACCEPTED <- largest observed acceptance 74 195 bytes REJECTED "exceeds maximum allowed tokens"
40 000 was CHOSEN inside that bracket, not measured directly: 62% of the largest observed acceptance (64 097), leaving room for roughly a 60% increase in token density before approaching the rejected end (74 195), and it matches an earlier, independent data point — a 40 282-byte response that is known to have arrived (2026-08-04, before this bisection existed).
The assumption this number rests on, stated plainly: the client's limit is in TOKENS; this budget counts BYTES. The bytes-per-token ratio is content-dependent (identifiers, hex digests and deep paths run denser than prose), so the margin above is NOT fixed — a byte count under budget can still cross a token ceiling the same client would reject. And the measurement is of ONE client, ONE date, ONE content shape: other MCP clients (Cursor, VSCode, OpenCode) have their own limits, unmeasured here.
Measured consequence of moving this number down (2026-08-09, same real project, fresh baseline): payload 39 962 bytes, 19 of 174 endpoints withheld (5 actionable, 14 frontier_pending) — at the old 60 000 this same project fit entirely with 0 withheld. Real mid-sized projects now see a non-zero withheld count where they previously did not; each bucket's `count` stays the complete number and codefit-scan-endpoint still fetches full detail on request (ADR 0054), but this is a user-visible behaviour change, not a free tightening.
See ADR 0062 for the full record, including what this number does NOT fix: a byte budget cannot guarantee a token limit. The structural answer — a hard cap on entries per bucket, so response size stops being a function of project size — is roadmap P0-4's declared follow-up, not this change.
The budget is DECLARED in the response (see BudgetBlock) and enforced by withholding the lowest-ranked endpoints, never by truncating the payload: a clipped response that reads like a complete one is the one outcome forbidden (ADR 0054, same principle as ADR 0048).
Variables ¶
This section is empty.
Functions ¶
func NewServer ¶
NewServer builds the codefit MCP server with its tools registered. Each tool is a THIN adapter: it hands the SDK's typed request to the core handler that already exists and is tested, and returns the core's result as structured output. No audit logic lives here — the MCP layer only connects the protocol to the engine (PRD §15). The server is stateless: every tool call is independent and carries everything it needs.
func Serve ¶
Serve runs the codefit MCP server over the stdio transport until ctx is cancelled. (HTTP/SSE is deferred; the SDK abstracts the transport, so it is added later without a refactor.)
func SupportedLanguageNames ¶ added in v0.2.8
func SupportedLanguageNames() []string
SupportedLanguageNames returns the canonical, deduplicated, sorted set of language names codefit-scan-all can resolve a security provider for — DERIVED from what languageProviders actually constructs (each entry's Language()), never a hand-written literal. This is the single source the nothing-measurable error message reads (D4/D5): a language and its aliases (ts/tsx) collapse to one canonical name here.
Types ¶
type ActionableSection ¶ added in v0.2.7
type ActionableSection struct {
Count int `json:"count"`
Withheld int `json:"withheld"`
Note string `json:"note,omitempty"`
// Endpoints is the rendered prefix of the ranked list: hardest gap kind first
// (affirmed → access → exposure → efficiency), then by certain-concern count.
Endpoints []report.ActionableEndpoint `json:"endpoints,omitempty"`
}
ActionableSection declares the endpoints codefit resolved locally AND found a gap in — the ones the agent acts on. They are NAMED with what it takes to rank them (counts, categories, gap kinds, best certainty, whether an affirmation is present) and their deterministic concerns in full; the surface question and signals text is one codefit-scan-endpoint call away.
Count is the COMPLETE number codefit classified as actionable and never the number rendered — Withheld accounts for the difference. Reading Count off len(Endpoints) is exactly the bug this section's shape exists to make impossible.
type BaselineAcceptRequest ¶
type BaselineAcceptRequest struct {
Root string `json:"root"`
Fingerprints []string `json:"fingerprints"`
Reason string `json:"reason"`
}
BaselineAcceptRequest marks baseline items as acknowledged by a human (a false positive or accepted debt). reason is mandatory. SAFETY: the agent must call this ONLY when the human decided so — codefit records by:"human" but cannot verify it; the skill enforces the discipline.
type BaselineAcceptResponse ¶
type BaselineAcceptResponse struct {
Accepted []string `json:"accepted"`
Note string `json:"note"`
}
BaselineAcceptResponse reports which fingerprints were acknowledged.
func HandleBaselineAccept ¶
func HandleBaselineAccept(req BaselineAcceptRequest) (BaselineAcceptResponse, error)
HandleBaselineAccept records a human's decision to accept items. It only touches the baseline file.
type BaselineDelta ¶
type BaselineDelta struct {
New int `json:"new"`
Changed int `json:"changed"`
Known int `json:"known"`
Acknowledged int `json:"acknowledged"`
Gone int `json:"gone"`
AffirmationsShown int `json:"affirmations_shown"`
GoneCandidates []GoneItem `json:"gone_candidates,omitempty"`
Note string `json:"note"`
}
BaselineDelta is scan-all's account of how the current scan compares to the committed baseline. The agent acts on new + changed (and unaccepted affirmations); known surface is silenced but counted.
type BaselineListRequest ¶
type BaselineListRequest struct {
Root string `json:"root"`
Language string `json:"language,omitempty"`
Filter string `json:"filter,omitempty"`
}
BaselineListRequest reads the current baseline so the agent can reference items in accept/prune WITHOUT reading the raw .codefit-baseline file. Filter is "" (all), "known" (not yet accepted), or "acknowledged". Language is accepted for tool uniformity but unused — listing reads the file, it does not scan code.
type BaselineListResponse ¶
type BaselineListResponse struct {
Items []baseline.Entry `json:"items"`
Count int `json:"count"`
AuthzHelpers []baseline.AuthzHelper `json:"authz_helpers,omitempty"`
Note string `json:"note"`
}
BaselineListResponse is the projected baseline: per item just fp+file+category+ state (+reason/date if acknowledged), small enough not to truncate. AuthzHelpers lists the project's registered custom authz helpers (read-only visibility) so the agent can see — and propose unregistering — them without reading the file.
func HandleBaselineList ¶
func HandleBaselineList(req BaselineListRequest) (BaselineListResponse, error)
HandleBaselineList returns the baseline entries. A missing baseline is NOT an error: it returns an empty list with a note pointing to scan-all. Read-only.
type BaselinePruneRequest ¶
type BaselinePruneRequest struct {
Root string `json:"root"`
Language string `json:"language"`
Fingerprints []string `json:"fingerprints,omitempty"`
}
BaselinePruneRequest removes baseline items that no longer exist in the code (gone). With Fingerprints set it prunes only those (if confirmed gone); empty prunes all confirmed-gone items.
type BaselinePruneResponse ¶
BaselinePruneResponse reports which fingerprints were pruned.
func HandleBaselinePrune ¶
func HandleBaselinePrune(req BaselinePruneRequest) (BaselinePruneResponse, error)
HandleBaselinePrune re-scans to confirm which baseline items are gone, then removes them. Stateless: it recomputes the current surface; it never edits code.
type BaselineRegisterAuthzHelperRequest ¶ added in v0.1.2
type BaselineRegisterAuthzHelperRequest struct {
Root string `json:"root"`
Language string `json:"language"`
HelperName string `json:"helper_name"`
Reason string `json:"reason"`
}
BaselineRegisterAuthzHelperRequest registers a project-specific authz helper so codefit recognizes it on later scans (known_authz_detected reflects it). reason is mandatory. SAFETY: registering silences the AUTHZ gap on EVERY item that calls the helper — far more reach than accepting one item. The agent must call this ONLY when the human approved it; codefit records by:"human" but cannot verify it (the skill enforces the discipline). It does NOT clear the IDOR/ownership gap (ADR 0013, ADR 0006 amended).
type BaselineRegisterAuthzHelperResponse ¶ added in v0.1.2
type BaselineRegisterAuthzHelperResponse struct {
Registered bool `json:"registered"`
Note string `json:"note"`
}
BaselineRegisterAuthzHelperResponse reports the outcome.
func HandleBaselineRegisterAuthzHelper ¶ added in v0.1.2
func HandleBaselineRegisterAuthzHelper(req BaselineRegisterAuthzHelperRequest) (BaselineRegisterAuthzHelperResponse, error)
HandleBaselineRegisterAuthzHelper records a human-approved custom authz helper in the baseline. It only touches the baseline file.
type BaselineUnregisterAuthzHelperRequest ¶ added in v0.1.2
type BaselineUnregisterAuthzHelperRequest struct {
Root string `json:"root"`
Language string `json:"language"`
HelperName string `json:"helper_name"`
}
BaselineUnregisterAuthzHelperRequest reverses a registration (the developer's decision is always reversible). The next scan stops recognizing the helper.
type BaselineUnregisterAuthzHelperResponse ¶ added in v0.1.2
type BaselineUnregisterAuthzHelperResponse struct {
Unregistered bool `json:"unregistered"`
Note string `json:"note"`
}
BaselineUnregisterAuthzHelperResponse reports the outcome.
func HandleBaselineUnregisterAuthzHelper ¶ added in v0.1.2
func HandleBaselineUnregisterAuthzHelper(req BaselineUnregisterAuthzHelperRequest) (BaselineUnregisterAuthzHelperResponse, error)
HandleBaselineUnregisterAuthzHelper removes a registered helper. It only touches the baseline file.
type BudgetBlock ¶ added in v0.2.7
type BudgetBlock struct {
Bytes int `json:"bytes"`
Withheld int `json:"withheld"`
Ordering string `json:"ordering"`
Note string `json:"note"`
}
BudgetBlock is scan-all's account of its own size. codefit's primary tool has to RETURN: a response an MCP client refuses is worth less than a smaller one that arrives. So the response declares the budget it is written to, and when the endpoint list does not fit it says exactly how many endpoints it is not showing and on what ordering it kept the ones it shows.
Withheld=0 still carries a Note, on purpose. "No mention of truncation" and "nothing was truncated" must not be the same bytes on the wire: that ambiguity is how a clipped response comes to read like a complete one (ADR 0048).
type CheckCVEsRequest ¶ added in v0.1.4
type CheckCVEsRequest struct {
Root string `json:"root"`
}
CheckCVEsRequest is the input to codefit-check-cves: a project root. The dependency manifests are auto-detected under it.
type CheckCVEsResponse ¶ added in v0.1.4
type CheckCVEsResponse struct {
Vulnerable []VulnerableDependency `json:"vulnerable"`
DependenciesScanned int `json:"dependencies_scanned"`
Notes []string `json:"notes"`
}
CheckCVEsResponse reports the vulnerable dependencies, how many were scanned, and any honest notes (a manifest present without its lockfile, or none found).
func HandleCheckCVEs ¶ added in v0.1.4
func HandleCheckCVEs(req CheckCVEsRequest) (CheckCVEsResponse, error)
HandleCheckCVEs reads the project's dependency manifests (exact versions from lockfiles / go.mod only), queries OSV.dev for known vulnerabilities, and returns the vulnerable dependencies. A thin adapter: it parses manifests, queries the client, and reshapes the result — no detection logic here. When no version resolves (no lockfile), it returns the honest note WITHOUT querying OSV.
type ConfirmSurfaceRequest ¶
type ConfirmSurfaceRequest struct {
Confirmations []surface.Confirmation `json:"confirmations"`
}
ConfirmSurfaceRequest carries the agent's verdicts back to codefit.
type ConfirmSurfaceResponse ¶
type ConfirmSurfaceResponse struct {
Findings []findings.Finding `json:"findings"`
Dismissed []surface.Confirmation `json:"dismissed"`
Uncertain []surface.Confirmation `json:"uncertain"`
Invalid []surface.Confirmation `json:"invalid"`
}
ConfirmSurfaceResponse is the integration result: probabilistic findings plus the traceability buckets. Stateless — built purely from the verdicts sent.
func HandleConfirmSurface ¶
func HandleConfirmSurface(req ConfirmSurfaceRequest) ConfirmSurfaceResponse
HandleConfirmSurface integrates the agent's verdicts: codefit-confirm-surface. It recomputes each surface id to validate the verdict before integrating, and keeps no session.
type CoverageRequest ¶
type CoverageRequest struct {
Language string `json:"language"`
}
CoverageRequest is the input to codefit-coverage.
type CoverageResponse ¶
CoverageResponse carries the coverage manifest: what is audited deterministically vs reasoned over surface vs not covered.
func HandleCoverage ¶
func HandleCoverage(req CoverageRequest) (CoverageResponse, error)
HandleCoverage returns the coverage manifest for the language. Thin adapter: the manifest is the provider's single source of truth.
type DBSection ¶ added in v0.2.0
type DBSection struct {
Measured bool `json:"measured"`
Note string `json:"note,omitempty"`
Findings []findings.Finding `json:"findings,omitempty"`
Surface []findings.SurfaceItem `json:"surface,omitempty"`
Score int `json:"score"`
}
DBSection is the database dimension's result inside scan-all. Measured=false with a Note is the honest "not audited" state (disabled / no parser / schema read or parse failure) — a db failure is SOFT here, reported but never fatal to the security result (ADR 0020). Findings are affirmations (e.g. DB-050); Surface are questions; both are already filtered by the baseline.
type FileInput ¶
FileInput is one source file a surface tool reasons over (path + content), so the tool stays stateless — the caller passes the bytes, codefit reads nothing.
type FrontierPending ¶
type FrontierPending struct {
Count int `json:"count"`
Withheld int `json:"withheld"`
Note string `json:"note,omitempty"`
Endpoints []report.FrontierEndpoint `json:"endpoints,omitempty"`
}
FrontierPending declares the endpoints codefit did NOT resolve locally: the data left the handler body, so codefit concluded nothing and the agent must follow it in the code. They are named (not detailed) with a Note explaining why they are not detailed and how to fetch any of them. This is not hiding — it is prioritising while declaring the rest.
type GoneItem ¶
type GoneItem struct {
Fingerprint string `json:"fingerprint"`
Category string `json:"category"`
File string `json:"file"`
Snippet string `json:"snippet,omitempty"`
}
GoneItem names a baseline item no longer present in the code — a prune candidate.
type ResolvedClean ¶
type ResolvedClean struct {
Count int `json:"count"`
Withheld int `json:"withheld"`
Note string `json:"note,omitempty"`
Endpoints []report.ResolvedCleanEndpoint `json:"endpoints,omitempty"`
}
ResolvedClean declares the endpoints codefit resolved locally and found clean (controls present, no gap). They are NAMED with a verification fact, not detailed. This is an affirmation — codefit looked and it is clean — not a generic "not detailed" bucket; that is why it is separate from FrontierPending.
type ScanAllRequest ¶
type ScanAllRequest struct {
Root string `json:"root"`
Language string `json:"language"`
// ChangedFiles narrows the audit to these project-relative paths (layer 0 of
// the filtering pyramid). codefit does not ask git which files changed — it
// has no power over the user's git, and the calling agent already knows what
// it touched. Absent or empty means a FULL audit, never "audit nothing".
//
// A narrowed run declares itself in the response's scope block, cannot mark a
// baseline item in an unopened file as gone, and leaves the DB dimension NOT
// MEASURED unless a configured schema path is in scope.
ChangedFiles []string `json:"changed_files,omitempty"`
}
ScanAllRequest is the input to codefit-scan-all: a project root and language. codefit walks the project, runs the deterministic sensor and the surface queries, and returns the complete per-endpoint picture.
type ScanAllResponse ¶
type ScanAllResponse struct {
Summary ScanAllSummary `json:"summary"`
// Scope declares how much of the project this response describes: mode full or
// partial, how many auditable files were in scope, and which requested paths
// the audit never reached. It is ALWAYS present, so a consumer never infers
// the mode from an absence and never reads a partial `blocked: false` as the
// wider claim it is not.
Scope ScopeBlock `json:"scope"`
// Score is the per-dimension breakdown plus the weighted global (ADR 0021). It
// is ALWAYS present: by_dimension carries every weighted dimension, with the
// unaudited ones (review/complexity/tests, and db when it did not run) as null —
// an honest statement that the dimension exists but was not measured. The score
// reflects deterministic AFFIRMATIONS only, not mapped surface.
Score scoring.ScoreSummary `json:"score"`
Baseline BaselineDelta `json:"baseline"`
// Budget declares the response's own byte budget and whether anything was
// withheld to meet it. ALWAYS present, including when nothing was withheld: an
// agent must be able to tell a complete list from a cut one by reading the
// response, never by guessing (ADR 0054).
Budget BudgetBlock `json:"budget"`
Actionable ActionableSection `json:"actionable"`
ResolvedClean ResolvedClean `json:"resolved_clean"`
FrontierPending FrontierPending `json:"frontier_pending"`
// Security reports whether the security dimension ran (D3b). It is ALWAYS
// present — deliberately NOT `omitempty`, unlike DB: the db dimension may
// legitimately not apply to a project (no database configured), but security
// applies to every project, so an ABSENT section could only mean an older
// codefit build. Measured=false with a Note is the honest "no provider for
// this language" state, mirroring DBSection's own Measured/Note shape.
Security SecuritySection `json:"security"`
// DB is the parallel database-structure section — the db dimension's findings
// and surface, baseline-filtered. It is NON-endpoint (a table has no route), so
// it is its own section, not one of the three endpoint buckets. Nil when the
// project has no database.schema_paths configured, so a project without a
// database yields a response byte-identical to before db was wired (ADR 0020).
DB *DBSection `json:"db,omitempty"`
}
ScanAllResponse is the agent-first synthesis as an ACTIONABLE summary, not the raw item dump. It has three buckets, one per resolution level, all decided by facts codefit already computes (ADR 0008):
- Actionable — resolved locally AND has a gap: full detail, the agent acts.
- ResolvedClean — resolved locally, NO gap: named + a verification fact; codefit checked and the controls are present.
- FrontierPending — not resolved locally (the data left the handler body): named; the agent follows it in the code.
ResolvedClean and FrontierPending are kept DISTINCT on purpose: one affirms codefit verified the controls, the other states codefit could not conclude — epistemological opposites the agent must distinguish (flattening them would be the old frontier-wording error). Full detail of any named endpoint is always one codefit-scan-endpoint call away. Note on the baseline layer: when a baseline exists, the three buckets are FILTERED to what is not yet tracked (new/changed surface, and unaccepted deterministic affirmations). So on an unchanged re-scan all three buckets can be empty even though Summary.CertainConcerns (computed before filtering) is > 0 — the difference is exactly the "known" surface the baseline is silencing.
func HandleScanAll ¶
func HandleScanAll(req ScanAllRequest) (ScanAllResponse, error)
HandleScanAll runs the full audit over the project and returns the actionable summary plus the named frontier-pending list. It reuses the real security sensor (the deterministic rules plus the three surface queries already run together there), groups the result by endpoint, and partitions by the local-resolution fact — it adds no detection, only the aggregation and the split.
type ScanAllSummary ¶
type ScanAllSummary struct {
Endpoints int `json:"endpoints"`
DeterministicFindings int `json:"deterministic_findings"`
SurfaceItems int `json:"surface_items"`
CertainConcerns int `json:"certain_concerns"`
}
ScanAllSummary is the at-a-glance count, not a judgment.
type ScanDBRequest ¶ added in v0.2.0
ScanDBRequest is the input to codefit-scan-db: a project root and language.
type ScanDBResponse ¶ added in v0.2.0
type ScanDBResponse struct {
Measured bool `json:"measured"`
Note string `json:"note,omitempty"`
Findings []findings.Finding `json:"findings"`
Surface []findings.SurfaceItem `json:"surface"`
Score int `json:"score"`
}
ScanDBResponse is the standalone DB-structure result. Measured distinguishes "audited" from "not audited": when false, Note says why (no schema_paths, no schema parser, or the sensor is disabled) and Findings/Surface are empty — it is NOT a "clean" result. Score is a plain dimension score (0-100), like codefit-scan-security; this tool does not compute by_dimension.
func HandleScanDB ¶ added in v0.2.0
func HandleScanDB(req ScanDBRequest) (ScanDBResponse, error)
HandleScanDB runs the DB sensor over the project and returns its structural findings + surface. A thin adapter: it resolves the provider, loads the config, and delegates to the DB sensor (which reads the schema, runs the core rules, and stamps identity). Standalone — it touches nothing in scan-all.
type ScanEndpointRequest ¶
type ScanEndpointRequest struct {
Root string `json:"root"`
Language string `json:"language"`
File string `json:"file"`
}
ScanEndpointRequest is the input to codefit-scan-endpoint: a project root, language, and the file (relative to root, as it appears in scan-all's File fields) to re-analyse on demand.
type ScanEndpointResponse ¶
type ScanEndpointResponse struct {
File string `json:"file"`
Found bool `json:"found"`
Endpoints []report.EndpointReport `json:"endpoints,omitempty"`
Note string `json:"note,omitempty"`
}
ScanEndpointResponse carries the full per-endpoint detail for one file: every handler in it with all its concerns (signals, reason_to_review, certainty, fact fields) — the same concern contract as scan-all. Found is false when the file has no auditable concerns (not a route handler, or nothing to enumerate).
func HandleScanEndpoint ¶
func HandleScanEndpoint(req ScanEndpointRequest) (ScanEndpointResponse, error)
HandleScanEndpoint re-analyses a single file on demand and returns its endpoints with full detail. STATELESS: it re-runs the static analysis over the project and filters to the requested file — it retrieves nothing stored. codefit does not keep the surface items waiting to be asked for; it recomputes the request. Static analysis is cheap, and re-running the same pipeline guarantees the detail here is identical to what scan-all would have shown for that endpoint (ADR 0008).
type ScanRequest ¶
type ScanRequest struct {
Root string `json:"root"`
Language string `json:"language"`
// ChangedFiles narrows the audit to these project-relative paths (layer 0 of
// the filtering pyramid). codefit does not ask git which files changed — it
// has no power over the user's git, and the calling agent already knows what
// it touched. Absent or empty means a FULL audit, never "audit nothing", and
// a narrowed run declares itself in the response's scope block.
ChangedFiles []string `json:"changed_files,omitempty"`
}
ScanRequest is the input to codefit-scan-security: a project root, a language, and optionally the files to narrow the audit to.
type ScanResponse ¶
type ScanResponse struct {
Findings []findings.Finding `json:"findings"`
Surface []findings.SurfaceItem `json:"surface"`
Score int `json:"score"`
Blocked bool `json:"blocked"`
Scope ScopeBlock `json:"scope"`
}
ScanResponse is the deterministic + surface result over the project (the §11 contract): flat findings and surface, the dimension score, and whether the project is blocked (an unconsented critical security finding). Scope declares how much of the project this result describes. It is ALWAYS present, so `blocked: false` is never read as a wider claim than it is.
func HandleScanSecurity ¶
func HandleScanSecurity(req ScanRequest) (ScanResponse, error)
HandleScanSecurity runs the security sensor over the project and returns the flat findings + surface. A thin adapter: it resolves the provider, runs the sensor (the deterministic rules + the surface queries, already wired there), and returns its result — no detection logic lives here.
type ScopeBlock ¶ added in v0.2.7
type ScopeBlock struct {
Mode string `json:"mode"`
Requested int `json:"requested"`
Audited int `json:"audited"`
AuditableTotal int `json:"auditable_total"`
Unmatched []string `json:"unmatched,omitempty"`
Note string `json:"note"`
}
ScopeBlock is a scan's account of HOW MUCH of the project it looked at. It exists because a partial audit that is indistinguishable from a full one is a lying auditor: the whole point of narrowing is that the narrowing stays visible.
- Requested is how many distinct files the caller asked for (canonical, so a path spelled twice counts once); 0 under a full scan.
- Audited is how many of them the pass actually examined, and AuditableTotal how many it COULD have — the denominator is the whole project, never the scope, or "3 of 412" collapses into a self-flattering "3 of 3".
- Unmatched are the requested paths the audit never reached: deleted, wrong extension, outside the project, inside a skipped directory. Without it an agent that passes three wrong paths gets "0 findings" and reads it as clean. Requested always equals Audited + len(Unmatched).
- Note is MANDATORY when partial and FORBIDDEN when full (see Validate).
func (ScopeBlock) Validate ¶ added in v0.2.7
func (s ScopeBlock) Validate() error
Validate enforces the honesty invariant in BOTH directions: a partial scan must declare itself in prose, and a full scan must not carry a caveat it has no basis for. Handlers call it before returning, so a violation is a loud error rather than an unlabelled partial result an agent would read as a full one — the failure this whole block exists to prevent.
type SecuritySection ¶ added in v0.2.8
SecuritySection reports whether the security dimension ran this pass (D3b). Measured=false is SOFT, exactly like DBSection: it never fails scan-all, it is reported. Note is empty when Measured is true (nothing to caveat) and non-empty otherwise, naming why (no provider resolved for the language) and what that means for the rest of the response (the schema may still have been audited; the code was not).
type SurfaceIDORRequest ¶
type SurfaceIDORRequest struct {
Files []FileInput `json:"files"`
}
SurfaceIDORRequest is the input to codefit-surface-idor.
type SurfaceResponse ¶
type SurfaceResponse struct {
Surface []findings.SurfaceItem `json:"surface"`
}
SurfaceResponse is the §11 surface contract: the items the agent must reason.
func HandleSurfaceAuthz ¶
func HandleSurfaceAuthz(req SurfaceIDORRequest) (SurfaceResponse, error)
HandleSurfaceAuthz enumerates the broken-authorization surface across the given files. It orders the items so the actionable ones — where no known authz helper was detected — come FIRST, the rest after (where a check exists, the agent verifies sufficiency). It does NOT reduce the list: the complete enumeration is preserved, only reordered, so findings surface instead of being buried in volume. Ordering by a fact is not a severity judgment — codefit does not say "no check is worse", it just surfaces the fact for the agent.
func HandleSurfaceIDOR ¶
func HandleSurfaceIDOR(req SurfaceIDORRequest) (SurfaceResponse, error)
HandleSurfaceIDOR enumerates the IDOR surface across the given files and returns it in the canonical JSON contract. Files that are not handled by a provider (or carry no IDOR surface) contribute nothing.
func HandleSurfaceNPlus1 ¶ added in v0.2.2
func HandleSurfaceNPlus1(req SurfaceIDORRequest) (SurfaceResponse, error)
HandleSurfaceNPlus1 enumerates the N+1 (DB-201) surface and orders by STRUCTURAL CERTAINTY, reusing the queryable facts — it does NOT filter (ADR 0005): a loop over three literal elements is enumerated exactly like a loop over an unbounded query result.
1st local + sequential await — the worst, most certain shape
2nd local + Promise.all-wrapped (concurrent) — still N queries
3rd frontier (a service/repository call — codefit cannot see the query;
kept last, honest, never dropped)
func HandleSurfaceOverfetch ¶
func HandleSurfaceOverfetch(req SurfaceIDORRequest) (SurfaceResponse, error)
HandleSurfaceOverfetch enumerates the over-fetching surface and orders by STRUCTURAL CERTAINTY, reusing the queryable facts — it does NOT filter:
1st local find, no select (structurally confirmed over-fetch — actionable) 2nd local find, with select (limited) 3rd frontier (service — codefit cannot see the find; kept last, honest)
The complete enumeration is preserved; only the order changes, lowering the uncertain (frontier) without dropping them — the unchecked-first principle on the local/frontier axis (ADR 0005). Ordering by a fact is not severity: codefit ranks by what it can assert with most certainty, the agent judges.
type Tool ¶
type Tool string
Tool is the name of an MCP tool codefit exposes. All tools use the codefit- prefix; the codefit-surface-* family enumerates surface for the agent to reason about rather than detecting (PRD section 11).
const ( ToolScanSecurity Tool = "codefit-scan-security" ToolScanDB Tool = "codefit-scan-db" ToolCheckCVEs Tool = "codefit-check-cves" ToolCheckPractices Tool = "codefit-check-practices" ToolScanTests Tool = "codefit-scan-tests" ToolSurfaceIDOR Tool = "codefit-surface-idor" ToolSurfaceAuthz Tool = "codefit-surface-authz" ToolSurfaceOverfetch Tool = "codefit-surface-overfetch" ToolSurfaceNPlus1 Tool = "codefit-surface-nplus1" ToolConfirmSurface Tool = "codefit-confirm-surface" ToolReviewCode Tool = "codefit-review-code" ToolScanAll Tool = "codefit-scan-all" ToolScanEndpoint Tool = "codefit-scan-endpoint" ToolBaselineList Tool = "codefit-baseline-list" ToolBaselineAccept Tool = "codefit-baseline-accept" ToolBaselinePrune Tool = "codefit-baseline-prune" ToolBaselineRegisterAuthzHelper Tool = "codefit-baseline-register-authz-helper" ToolBaselineUnregisterAuthzHelper Tool = "codefit-baseline-unregister-authz-helper" ToolCoverage Tool = "codefit-coverage" )
type VulnerableDependency ¶ added in v0.1.4
type VulnerableDependency struct {
Name string `json:"name"`
Version string `json:"version"`
Ecosystem string `json:"ecosystem"`
Vulnerabilities []cve.Vulnerability `json:"vulnerabilities"`
}
VulnerableDependency is one dependency that OSV.dev reports as vulnerable, with every vulnerability affecting its exact installed version.