feat(cliv2): enable CaptureEngine billing lifecycle [IANDT-240] - #7067
feat(cliv2): enable CaptureEngine billing lifecycle [IANDT-240]#7067brettgurman-snyk wants to merge 7 commits into
Conversation
…-240] Create one command-scoped capture bag for workflow and legacy proxy traffic, call clibilling.Finish from tearDown on exit code 0, and remove the bespoke legacy_contributor_billing emit path. Requires GAF 237+238; use local replace for development until those land on main. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
⛔ Snyk checks have failed. 2 issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Delegate bag lifecycle to GAF CaptureEngine (begin/finish at command boundaries). Remove cliv2 networkinjector ctx and legacycli capture duplication; GAF HTTP transport injection handles legacy proxy traffic. Co-authored-by: Cursor <cursoragent@cursor.com>
|
…[IANDT-240] Remove contributor_billing.go wrapper; host lifecycle helpers now live in GAF. Co-authored-by: Cursor <cursoragent@cursor.com>
Use pseudo-version from go-application-framework #681 so CI can compile pkg/clibilling before the tagged release. Co-authored-by: Cursor <cursoragent@cursor.com>
Drop BeginCommand and WithContributorBillingCapture; capture opens on first billable HTTP and FinishCommand at teardown emits. Pin GAF to lazy-open stack. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Verification results
Auto-approval check: this PR is not limited to a dependency bump. Besides the cliv2/go.mod/cliv2/go.sum version bump for go-application-framework, it also changes real logic in cliv2/pkg/core/main.go (wires clibilling.EnableIfConfigured into engine creation, adds clibilling.FinishCommand to teardown, and adds workflow.WithContext(globalContext) to the legacy-CLI invocation). Per policy, only pure dependency-bump PRs are auto-approved, so this one is not being auto-approved. I'm also not requesting changes (per policy this automation never sets a CHANGES_REQUESTED status) — see the findings below for the maintainers to weigh.
Four independent review passes (semantic analysis, adversarial review, security scan, code review) converged on the same core issue, so I'm confident in flagging it even though I'm not blocking the PR.
Critical
cliv2/pkg/core/main.go:549—clibilling.FinishCommand(teardownCtx, globalEngine, globalConfiguration, exitCode == 0)uses the process exit code as the billing-success signal. ButexitCodealso encodes "scan found issues" (e.g.iac test --report— one of the two commandsclibilling.IsBillableCommandreturnstruefor — exits non-zero on its normal, expected outcome).finalizeContributorBillingskips emission wheneversuccessisfalse, so a successful, billable scan that merely reports findings has its captured billing session silently discarded — defeating the PR's own purpose for its headline use case.cliv2/pkg/core/main.go:549— The wait for pending billing emits scales asnumRecords * 5sand is not bounded byteardownCtx's own 5s deadline (the wait is a rawtime.Duration, decoupled from the context). Any command capturing more than one billing record can make CLI process exit hang well past the 5s budget thatteardownCtx/teardownTimeoutwas explicitly introduced to guarantee.- Related:
clibilling.EnableIfConfiguredregisters a GAF post-invoke hook that closes/discards the capture bag on any top-levelInvokeerror.WORKFLOWID_REPORT_ANALYTICS(viasendInstrumentation) andWORKFLOWID_GLOBAL_CLEANUP, both invoked earlier in the sametearDown, are not exempted from this hook — so a transient analytics/cleanup failure beforeFinishCommandruns can discard billing data for an otherwise fully successful command.
Should Fix
cliv2/pkg/core/main.go:549—FinishCommand'sboolreturn value (whether emission completed before the wait budget elapsed) is discarded. Every sibling teardown step in this function logs its outcome; this one fails silently, hiding exactly the failure mode above.- No test coverage was added for the new wiring (
EnableIfConfiguredordering beforeInit(), orFinishCommand's derivedsuccessvalue across exit-code cases).
Suggestion
cliv2/go.mod:25— Pinned to a pre-release pseudo-version corresponding to an upstream PR (go-application-framework#681) that is still in draft. Already flagged by the PR's own comment/description as needing a re-pin before merge — just noting it renders here as well.- GitHub's security check on this head commit reports "Open Source Security: 2 High", but since no dependency other than the
go-application-frameworkself-reference changed ingo.sum, these findings (if genuine) most likely predate this diff rather than being introduced by it. Could not verify details without authenticated Snyk access — worth a human look.
Build, go vet, and go test ./pkg/core/... all pass against the pinned pre-release, and go mod tidy shows no drift, so the dependency bump itself is mechanically clean — the concerns above are all about the new main.go wiring logic.
Sent by Cursor Automation: Automatic PR verification


Summary
Minimal cliv2 host adapter for IANDT-240 lazy-open contributor billing. Registers GAF failure-cleanup hook and calls
FinishCommandat tearDown. Capture session opens inside GAF middleware on first billable HTTP — not at command start.Requires GAF stack: #664 → #671 → #681 (pinned pre-release below).
Lazy-open flow
Removed from earlier draft:
BeginCommand,WithContributorBillingCapture(),syncActiveBillingCommand/ config-key approach.Diff vs
maincliv2/pkg/core/main.goEnableIfConfiguredat engine creation;FinishCommandintearDown; removedBeginCommandandWithContributorBillingCapture()cliv2/go.mod/go.sumv0.10.1-0.20260806080023-f868e847d10f); localreplacecommented out for CINo
contributor_billing.go— lifecycle helpers live in GAFpkg/clibilling.cliv2 wiring
Build locally with
-tags application(go build -tags application -o ~/bin/snyk-billing ./cmd/cliv2).Test plan
make lint+make testin cliv2snyk monitor→ mitmweb shows ingest POST at tearDown)Merge order
GAF #664 → #671 → #681 → this PR → E2E