Documentation
¶
Overview ¶
Deploy-repo scaffold + creation (mallcoppro-f3b): `mallcop init --create-repo owner/name` turns the plain local scaffold runInit already writes (mallcop.yaml, store/, events.jsonl) into a customer DEPLOYMENT repo pushed to a real GitHub repository, so the customer never compiles mallcop locally — a scheduled GitHub Action does.
Rulings this file implements:
- D1 THIN-EMBED: the repo pins mallcop via go.mod (require github.com/mallcop-app/mallcop <version>) so a customer authoring a detectors/<name> sidecar gets the real core/detect + pkg/detectorhost types from the published module — never a fork, never vendored source.
- D2+2fd WASM SIDECARS: the scaffolded CI workflow builds each detectors/<name> to wasip1 .wasm into detectors/bin/ (matching cfg.Detectors.Sidecars.Dir's default — see resolveSidecarsDir in sidecars.go). It NEVER rebuilds the whole mallcop binary from customer code — the core binary is always the pinned prebuilt release tarball downloaded from GitHub Releases.
- D3 SAME-REPO: findings live in store/ inside the SAME GitHub repo, not a separate one. store/ is (per core/store's own design — see openOrInitStore in scan.go) its own nested git repository, so it can't ride along on the deployment repo's main branch across ephemeral Actions runs. The scaffolded workflow instead backs store/ with a dedicated branch (mallcopFindingsBranch) of the SAME repo: restore it before the scan, push it back after. Main branch's .gitignore excludes store/ so an operator's ordinary "git add -A" on main can never swallow findings history into the wrong branch.
GitHub App authorize seam (explicit, NOT exercised by this item's live proof): mallcop-pro already holds the GitHub App private key server-side and exposes POST /v1/github/token (see mallcop-pro/internal/server/github_token.go) to exchange a customer's donut-rail API key + their App installation_id for a scoped installation access token. proAppToken below implements that exact exchange and is unit tested against an httptest stand-in of the endpoint. It is not exercised against the live api.mallcop.app here — that needs a funded customer account and a real App installation, which is out of scope for the smallest honest v1 (see the item's DISCOVER FIRST note). The transport actually exercised live is envGitHubToken: a raw token from an environment variable (e.g. `gh auth token`'s output), used as a personal access token would be.
Package cli implements the full mallcop CLI as an importable package. An external module can embed the entire CLI with:
import "github.com/mallcop-app/mallcop/cli"
func main() { cli.Main() }
The embedder controls its own detector linkage the same way cmd/mallcop does: blank-import whatever detect.Register-ing package(s) it wants before calling cli.Main() (core/detect/authored, or an external equivalent). This package intentionally does NOT import core/detect/authored itself — that blank import is the human-wired registration seam and belongs to the binary's main package, not to this reusable library.
Usage:
mallcop scan [--config <mallcop.yaml>] | --store <dir> [--events <file> | --connector github --github-org <org>] [--tuning <yaml>] [--json] mallcop detect [--baseline <path>] [--tuning <yaml>] < events.jsonl > findings.jsonl mallcop exam-detect [--json] [--tuning <yaml>] mallcop validate-proposal --base <ref> [--head <ref>] [--guard-only] [--allow-no-coverage-gain] [--json] mallcop collect --store <dir> [--fidelity <json>] [--json] mallcop init [--dir <path>] [--pro] [--create-repo owner/name] [--mallcop-version <tag>] [--github-token-env <VAR>] mallcop migrate [--dir <path>] [--mallcop-version <tag>] [--config-only] [--dry-run] mallcop status --store <dir> mallcop config mallcop config set connector --kind=file|github|cloud --id=<id> [...] mallcop config set autonomy <non|semi|fully> mallcop feedback <finding_id> approve|dismiss --store <dir> [--reason <text>] [--by <name>] mallcop investigate --question <text> --store <dir> [--baseline <path>] | --serve --inbox <file> --outbox <file> --store <dir>
In-place deploy-repo upgrade (mallcoppro-973): `mallcop migrate` re-rigs an EXISTING customer deployment repo to the current schema + pinned release, so a live customer can bump versions without a hand re-scaffold.
The v0.10.0 config loader (core/config) is a STRICT decoder: an old-shape mallcop.yaml (v0.9.3 and earlier — `secrets:`/`routing:`/`actor_chain:`/ `pro:` blocks, `connectors:` as a kind->cfg MAP) is a loud load error, so every pre-v0.10 deploy repo's workflows fail the moment they read the config ("field secrets not found", "connectors: cannot unmarshal map into []Connector", "field routing not found"). This command performs the exact re-rig reproduced against the customer0 fixture:
- mallcop.yaml — legacy shape -> the new strict schema (config.Config), carrying over what maps (github org, findings budget, the donut rail) and LOUDLY reporting every dropped key rather than silently eating it.
- .github/workflows/ — force-refresh scan.yml AND add the (v0.10) new mallcop-investigate.yml, both pinned to the target release.
- go.mod — bump the github.com/mallcop-app/mallcop require to the target release so CI sidecar builds match the workflow's downloaded binary.
It is offline and in-place: it rewrites files under --dir (a checked-out deploy repo). Committing + pushing the result is the operator's step (the printed next-steps), the same division of labor as `mallcop init` vs `mallcop init --create-repo`. Setting the MALLCOP_API_KEY repo secret is likewise printed as the exact `gh secret set` command (mallcoppro-7b1's live GitHub-secret-API path is deferred — see the item).
Index ¶
Constants ¶
const CollectSchemaVersion = 1
CollectSchemaVersion is the collect-envelope wire-format version. It is the STABLE PROCESS BOUNDARY between mallcop (this repo) and the mallcop-pro proposer: mallcop-pro must NOT import mallcop (separate Go modules), so it consumes the collectors as JSON over `mallcop collect --json` and duplicates the MappingGap / GapCandidate structs on its side. Bump this on any backwards-incompatible change to the envelope shape, exactly as selfgate.GateSchemaVersion versions the validate-proposal wire format.
Variables ¶
This section is empty.
Functions ¶
func Main ¶
func Main()
Main is the CLI entrypoint. It parses os.Args (via the flag package's default CommandLine), dispatches to the requested subcommand, and calls os.Exit with the same exit codes cmd/mallcop has always used:
0 success 1 findings detected (scan / detect / exam-detect / validate-proposal) 2 any other command failure
Callers (cmd/mallcop's main.go, or an external embedder) are expected to blank-import their detector registration package(s) before calling Main, then simply call cli.Main() as their entire main().