feat(reporter): add suppressible Pro conversion CTA to human-facing reports - #105
feat(reporter): add suppressible Pro conversion CTA to human-facing reports#105affaan-m wants to merge 1 commit into
Conversation
…eports Monetize the free funnel (ecc-agentshield is ~30K downloads/month) with a single tasteful footer line that leads with the privacy + low-noise wedge: 'Scans run locally; nothing leaves your machine. Track fleet posture and drift over time with ECC Tools Pro'. Points at the real GitHub App (github.com/apps/ecc-tools). - New src/reporter/cta.ts: shared CTA copy + opt-out (ECC_NO_CTA / AGENTSHIELD_NO_CTA; empty/0/false do not suppress). - Terminal footer + markdown report footer. The GitHub Action job summary reuses renderMarkdownReport, so it inherits the CTA automatically. - Deliberately NOT added to JSON or SARIF (machine-consumed output stays clean). - The free, local-first, zero-account scanner stays the moat; the CTA only points at the hosted/fleet upgrade. 9 new test assertions (cta.test.ts + a markdown-vs-json integration check). Full suite green (1868), tsc + eslint clean, CLI smoke verified (footer shows by default, ECC_NO_CTA=1 suppresses).
|
ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR. |
|
Note
|
| Layer / File(s) | Summary |
|---|---|
CTA module: constants, suppression, and line generators src/reporter/cta.ts, tests/reporter/cta.test.ts |
Exports PRO_CTA_PLAIN and PRO_CTA_MARKDOWN string templates, ctaSuppressed() that checks ECC_NO_CTA/AGENTSHIELD_NO_CTA env vars, and proCtaPlainLines/proCtaMarkdownLines that return footer lines or an empty array. Tests verify content, default-enabled behavior, suppression on truthy values, and non-suppression on falsy-like values ("", "0", "false"). |
Terminal and markdown reporter CTA integration src/reporter/terminal.ts, src/reporter/json.ts, tests/reporter/json.test.ts |
renderTerminalReport iterates proCtaPlainLines() and appends each line with chalk.dim before the final blank line. The markdown renderer in json.ts appends proCtaMarkdownLines() after the findings block. Tests assert "ECC Tools Pro" and the GitHub Apps URL appear in markdown output and are absent from renderJsonReport output. |
Estimated code review effort
🎯 2 (Simple) | ⏱️ ~10 minutes
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title accurately and concisely describes the main change: adding a suppressible Pro conversion CTA to human-facing reports, which is the core feature introduced across all modified files. |
| Docstring Coverage | ✅ Passed | Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feat/pro-cta-footer
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
| it("appends the Pro CTA footer (human-facing markdown only)", () => { | ||
| const output = renderMarkdownReport(makeReport()); | ||
| expect(output).toContain("ECC Tools Pro"); | ||
| expect(output).toContain("https://github.com/apps/ecc-tools"); | ||
| // JSON output stays machine-clean: no marketing string. | ||
| expect(renderJsonReport(makeReport())).not.toContain("ECC Tools Pro"); | ||
| }); |
There was a problem hiding this comment.
Integration test is environment-sensitive
renderMarkdownReport calls proCtaMarkdownLines() with no argument, so it reads from process.env directly. The assertion expect(output).toContain("ECC Tools Pro") will therefore fail whenever ECC_NO_CTA=1 or AGENTSHIELD_NO_CTA=1 is present in the test environment — which is exactly what the PR's own documented opt-out guidance tells CI users to set. A developer or CI pipeline that follows the suppression guidance and then runs npm test will see this test break.
The unit tests in cta.test.ts correctly inject a controlled env object, but this integration test bypasses that isolation. The fix is to either use vi.stubEnv / vi.unstubAllEnvs around this test, or delete the two env vars from process.env for the duration of the test.
Monetizes the free funnel (
ecc-agentshieldis doing ~30K downloads/month with near-zero bridge to paid). Adds a single, tasteful footer line to human-facing reports — no behavior change to detection, no noise in machine output.What
src/reporter/cta.ts: shared CTA copy + opt-out logic.renderMarkdownReport, so it inherits the CTA automatically (third surface, zero extra code).Wedge
Leads with the privacy + low-noise differentiators (local-first, zero-account) and points at the real ECC Tools GitHub App. The free scanner stays the moat; the CTA only points at the hosted/fleet upgrade.
Opt-out
Suppress with
ECC_NO_CTA=1orAGENTSHIELD_NO_CTA=1(empty /0/falsedo not suppress) — for clean CI logs and scripted use.Verification
tests/reporter/cta.test.ts+ a markdown-vs-json integration check injson.test.ts).tsc --noEmit+eslintclean.ECC_NO_CTA=1suppresses the CTA while keeping the existing footer.Summary by CodeRabbit
Release Notes
New Features
Tests
Greptile Summary
Adds a suppressible Pro conversion CTA to the human-facing report surfaces (terminal footer and markdown/GitHub Action job summary) while keeping JSON and SARIF output machine-clean. The implementation is clean and well-scoped — new
src/reporter/cta.tscentralises copy and opt-out logic, the two report renderers each call the appropriate helper, and the CTA unit tests use env injection for full determinism.src/reporter/cta.tsintroducesctaSuppressed,proCtaPlainLines, andproCtaMarkdownLineswith injectable env parameters, correct opt-out semantics (ECC_NO_CTA/AGENTSHIELD_NO_CTA), and separate plain-text and markdown variants.renderMarkdownReport(which also backs the GitHub Action job summary) appends the markdown CTA;renderTerminalReportappends the plain-text CTA;renderJsonReportis untouched.json.test.tsasserts CTA presence using realprocess.env, making it fragile if the documented opt-out env vars are set in the test environment.Confidence Score: 4/5
Safe to merge with one test fix — no scanner logic, output formats, or security analysis paths are affected.
The integration test in json.test.ts asserts that "ECC Tools Pro" appears in the markdown output, but it calls renderMarkdownReport without injecting the env object, so it reads from real process.env. Any CI that has ECC_NO_CTA=1 set — following the PR's own opt-out guidance — will see this assertion fail. The rest of the change is clean: the source module, the two renderer edits, and the dedicated CTA unit tests are all correct.
tests/reporter/json.test.ts — the new integration test case needs env isolation (vi.stubEnv or explicit env deletion) to match the deterministic pattern used in cta.test.ts.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[SecurityReport] --> B[renderTerminalReport] A --> C[renderMarkdownReport] A --> D[renderJsonReport] A --> E[SARIF renderer] B --> F[proCtaPlainLines] C --> G[proCtaMarkdownLines] D --> H[No CTA — machine-clean] E --> I[No CTA — machine-clean] F --> J{ctaSuppressed?} G --> J J -- ECC_NO_CTA / AGENTSHIELD_NO_CTA set --> K[Returns empty array] J -- Not suppressed --> L[Returns CTA lines] K --> M[Footer unchanged] L --> N[CTA appended to footer]%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% flowchart TD A[SecurityReport] --> B[renderTerminalReport] A --> C[renderMarkdownReport] A --> D[renderJsonReport] A --> E[SARIF renderer] B --> F[proCtaPlainLines] C --> G[proCtaMarkdownLines] D --> H[No CTA — machine-clean] E --> I[No CTA — machine-clean] F --> J{ctaSuppressed?} G --> J J -- ECC_NO_CTA / AGENTSHIELD_NO_CTA set --> K[Returns empty array] J -- Not suppressed --> L[Returns CTA lines] K --> M[Footer unchanged] L --> N[CTA appended to footer]Reviews (1): Last reviewed commit: "feat(reporter): add suppressible Pro con..." | Re-trigger Greptile