Skip to content

Commit d3d8cdc

Browse files
PR feedback: rename symbols, remove codex stub, fix hook naming, update tests
- Rename scanFiles → scanFilesForSecrets in secrets-scan.ts - Rename callbackCommand → hookCommand in command-tree.ts - Remove codex-pre-tool-use command (out of scope) - Remove PR-specific comments from command-tree.ts - Rename agent-prompt-submit → claude-prompt-submit - Rename agent-post-tool-use → claude-post-tool-use - Consolidate duplicate hook.test.ts tests, assert description shown - Update README.md via gen:docs
1 parent bf10cc2 commit d3d8cdc

10 files changed

Lines changed: 66 additions & 49 deletions

File tree

README.md

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ Revoke a user token
154154
sonar api post "/api/user_tokens/revoke" --data '{"name":"my-token"}'
155155
```
156156

157+
157158
---
158159

159160
### `sonar integrate`
@@ -180,7 +181,7 @@ Setup SonarQube integration for Claude Code. This will install secrets scanning
180181

181182
| Option | Type | Required | Description | Default |
182183
| ------------------- | ------- | -------- | --------------------------------------------------------------------------- | ------- |
183-
| `--project`, `-p` | string | No | Project key | - |
184+
| `--project`, `-p` | string | No | SonarCloud project key (overrides auto-detected project) | - |
184185
| `--non-interactive` | boolean | No | Non-interactive mode (no prompts) | - |
185186
| `--global`, `-g` | boolean | No | Install hooks and config globally to ~/.claude instead of project directory | - |
186187

@@ -391,6 +392,40 @@ Update sonar CLI to the latest version
391392

392393
---
393394

395+
### `sonar hook`
396+
397+
Internal callback handlers for agent and git hooks
398+
399+
#### `sonar hook claude-pre-tool-use`
400+
401+
PreToolUse handler: scan files for secrets before agent reads them
402+
403+
---
404+
405+
#### `sonar hook codex-pre-tool-use`
406+
407+
PreToolUse handler for Codex: scan files for secrets before agent reads them
408+
409+
---
410+
411+
#### `sonar hook agent-prompt-submit`
412+
413+
UserPromptSubmit handler: scan prompts for secrets before sending
414+
415+
---
416+
417+
#### `sonar hook agent-post-tool-use`
418+
419+
PostToolUse handler: run SQAA analysis on modified files
420+
421+
**Options:**
422+
423+
| Option | Type | Required | Description | Default |
424+
| ----------------- | ------ | -------- | ---------------------- | ------- |
425+
| `--project`, `-p` | string | No | SonarCloud project key | - |
426+
427+
---
428+
394429
## Option Types
395430

396431
- `string` — text value (e.g. `--server https://sonarcloud.io`)
@@ -425,7 +460,7 @@ Both are enabled by default and share the same opt-out toggle. To disable all da
425460
sonar config telemetry --disabled
426461
```
427462

428-
No personally identifiable information is transmitted. File paths in error reports are anonymized by replacing your home directory with `~`.
463+
No personally identifiable information is transmitted.
429464

430465
## Contributing
431466

src/cli/command-tree.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -232,36 +232,27 @@ COMMAND_TREE.command('self-update')
232232

233233
// Hidden callback command — internal handlers for agent and git hooks.
234234
// Shell hook scripts call `sonar hook <event>` to delegate all business logic to TypeScript.
235-
export const callbackCommand = COMMAND_TREE.command('hook', { hidden: true })
235+
export const hookCommand = COMMAND_TREE.command('hook', { hidden: true })
236236
.description('Internal callback handlers for agent and git hooks')
237237
.enablePositionalOptions()
238238
.anonymousAction(function (this: Command) {
239239
this.outputHelp();
240240
});
241241

242-
callbackCommand
242+
hookCommand
243243
.command('claude-pre-tool-use')
244244
.description('PreToolUse handler: scan files for secrets before agent reads them')
245245
.anonymousAction(() => claudePreToolUse());
246246

247-
// codex-pre-tool-use reuses the same handler (same hook event, different agent name)
248-
callbackCommand
249-
.command('codex-pre-tool-use')
250-
.description('PreToolUse handler for Codex: scan files for secrets before agent reads them')
251-
.anonymousAction(() => claudePreToolUse());
252-
253-
// agent-prompt-submit and agent-post-tool-use are installed by `sonar integrate claude`.
254-
// They are implemented in subsequent PRs; stubs here ensure scripts don't fail with
255-
// "unknown command" on a CLI that only has CLI-244/245.
256-
callbackCommand
257-
.command('agent-prompt-submit')
247+
hookCommand
248+
.command('claude-prompt-submit')
258249
.description('UserPromptSubmit handler: scan prompts for secrets before sending')
259250
.anonymousAction(() => {
260251
return;
261252
});
262253

263-
callbackCommand
264-
.command('agent-post-tool-use')
254+
hookCommand
255+
.command('claude-post-tool-use')
265256
.option('-p, --project <project>', 'SonarCloud project key')
266257
.description('PostToolUse handler: run SQAA analysis on modified files')
267258
.anonymousAction(() => {

src/cli/commands/hook/claude-pre-tool-use.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { existsSync } from 'node:fs';
2525
import { resolveAuth } from '../../../lib/auth-resolver';
2626
import logger from '../../../lib/logger';
2727
import { readStdinJson } from './stdin';
28-
import { resolveSecretsBinaryPath, scanFiles, EXIT_CODE_SECRETS_FOUND } from './secrets-scan';
28+
import { resolveSecretsBinaryPath, scanFilesForSecrets, EXIT_CODE_SECRETS_FOUND } from './secrets-scan';
2929

3030
interface PreToolUsePayload {
3131
tool_name?: string;
@@ -52,7 +52,7 @@ export async function claudePreToolUse(): Promise<void> {
5252
if (!binaryPath) return; // binary not installed — allow gracefully
5353

5454
try {
55-
const exitCode = await scanFiles(binaryPath, [filePath], auth);
55+
const exitCode = await scanFilesForSecrets(binaryPath, [filePath], auth);
5656
if (exitCode === EXIT_CODE_SECRETS_FOUND) {
5757
process.stdout.write(
5858
JSON.stringify({

src/cli/commands/hook/secrets-scan.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function resolveSecretsBinaryPath(): string | null {
4949
* Run secrets scan on the given files. Returns the binary exit code.
5050
* May throw on timeout; other errors are surfaced as non-zero exit codes.
5151
*/
52-
export async function scanFiles(
52+
export async function scanFilesForSecrets(
5353
binaryPath: string,
5454
files: string[],
5555
auth: ResolvedAuth,

src/cli/commands/integrate/claude/hook-templates.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,17 @@ export function getSecretPreToolTemplateWindows(): string {
4545
}
4646

4747
export function getSecretPromptTemplateUnix(): string {
48-
return unixTemplate('sonar hook agent-prompt-submit');
48+
return unixTemplate('sonar hook claude-prompt-submit');
4949
}
5050

5151
export function getSecretPromptTemplateWindows(): string {
52-
return windowsTemplate('sonar hook agent-prompt-submit');
52+
return windowsTemplate('sonar hook claude-prompt-submit');
5353
}
5454

5555
export function getSqaaPostToolTemplateUnix(projectKey: string): string {
56-
return unixTemplate(`sonar hook agent-post-tool-use --project ${projectKey}`);
56+
return unixTemplate(`sonar hook claude-post-tool-use --project ${projectKey}`);
5757
}
5858

5959
export function getSqaaPostToolTemplateWindows(projectKey: string): string {
60-
return windowsTemplate(`sonar hook agent-post-tool-use --project ${projectKey}`);
60+
return windowsTemplate(`sonar hook claude-post-tool-use --project ${projectKey}`);
6161
}

tests/integration/specs/hook/hook.test.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,11 @@ describe('sonar hook', () => {
4545
);
4646

4747
it(
48-
'sonar hook --help exits 0 and shows usage',
49-
async () => {
50-
const result = await harness.run('hook --help');
51-
expect(result.exitCode).toBe(0);
52-
expect(result.stdout).toContain('hook');
53-
},
54-
{ timeout: 15000 },
55-
);
56-
57-
it(
58-
'sonar hook exits 0 (shows help)',
48+
'sonar hook exits 0 and shows command description',
5949
async () => {
6050
const result = await harness.run('hook');
6151
expect(result.exitCode).toBe(0);
52+
expect(result.stdout).toContain('Internal callback handlers for agent and git hooks');
6253
},
6354
{ timeout: 15000 },
6455
);

tests/integration/specs/integrate/claude.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ describe('integrate claude', () => {
426426
{ timeout: 30000 },
427427
);
428428
it(
429-
'prompt-secrets.sh uses correct subcommand (sonar hook agent-prompt-submit) after integration',
429+
'prompt-secrets.sh uses correct subcommand (sonar hook claude-prompt-submit) after integration',
430430
async () => {
431431
const server = await harness
432432
.newFakeServer()
@@ -445,7 +445,7 @@ describe('integrate claude', () => {
445445
const promptScriptContent = harness.cwd
446446
.file('.claude', 'hooks', 'sonar-secrets', 'build-scripts', 'prompt-secrets.sh')
447447
.asText();
448-
expect(promptScriptContent).toContain('sonar hook agent-prompt-submit');
448+
expect(promptScriptContent).toContain('sonar hook claude-prompt-submit');
449449
expect(promptScriptContent).not.toContain('sonar analyze --file');
450450
},
451451
{ timeout: 30000 },

tests/unit/hook-pre-tool-use.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('claudePreToolUse', () => {
5151
resolveSecretsBinaryPathSpy = spyOn(secretsScan, 'resolveSecretsBinaryPath').mockReturnValue(
5252
'/usr/bin/sonar-secrets',
5353
);
54-
scanFilesSpy = spyOn(secretsScan, 'scanFiles').mockResolvedValue(0);
54+
scanFilesSpy = spyOn(secretsScan, 'scanFilesForSecrets').mockResolvedValue(0);
5555
existsSyncSpy = spyOn(fs, 'existsSync').mockReturnValue(true);
5656
});
5757

tests/unit/hook-templates.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ describe('Secret Scanning Hook Templates', () => {
6060
const template = getSecretPromptTemplateUnix();
6161

6262
expect(template.startsWith('#!/bin/bash')).toBe(true);
63-
expect(template.includes('sonar hook agent-prompt-submit')).toBe(true);
63+
expect(template.includes('sonar hook claude-prompt-submit')).toBe(true);
6464
expect(template.includes(UNIX_SONAR_COMMAND_GUARD)).toBe(true);
6565
});
6666

@@ -74,7 +74,7 @@ describe('Secret Scanning Hook Templates', () => {
7474
it('UserPromptSubmit Windows hook: delegates to sonar hook', () => {
7575
const template = getSecretPromptTemplateWindows();
7676

77-
expect(template.includes('sonar hook agent-prompt-submit')).toBe(true);
77+
expect(template.includes('sonar hook claude-prompt-submit')).toBe(true);
7878
expect(template.includes(WINDOWS_SONAR_COMMAND_GUARD)).toBe(true);
7979
});
8080
});
@@ -84,7 +84,7 @@ describe('SQAA PostToolUse Hook Templates', () => {
8484
const template = getSqaaPostToolTemplateUnix('my-project');
8585

8686
expect(template.startsWith('#!/bin/bash')).toBe(true);
87-
expect(template.includes('sonar hook agent-post-tool-use')).toBe(true);
87+
expect(template.includes('sonar hook claude-post-tool-use')).toBe(true);
8888
expect(template.includes('--project my-project')).toBe(true);
8989
expect(template.includes(UNIX_SONAR_COMMAND_GUARD)).toBe(true);
9090
});
@@ -100,7 +100,7 @@ describe('SQAA PostToolUse Hook Templates', () => {
100100
it('PostTool Windows hook: delegates to sonar hook with project key', () => {
101101
const template = getSqaaPostToolTemplateWindows('my-project');
102102

103-
expect(template.includes('sonar hook agent-post-tool-use')).toBe(true);
103+
expect(template.includes('sonar hook claude-post-tool-use')).toBe(true);
104104
expect(template.includes('--project my-project')).toBe(true);
105105
expect(template.includes(WINDOWS_SONAR_COMMAND_GUARD)).toBe(true);
106106
});
@@ -150,11 +150,11 @@ describe('Template Integrity', () => {
150150
});
151151
});
152152

153-
it('SQAA template routes to agent-post-tool-use, secrets templates route to other events', () => {
154-
expect(getSqaaPostToolTemplateUnix('proj').includes('agent-post-tool-use')).toBe(true);
155-
expect(getSqaaPostToolTemplateWindows('proj').includes('agent-post-tool-use')).toBe(true);
153+
it('SQAA template routes to claude-post-tool-use, secrets templates route to other events', () => {
154+
expect(getSqaaPostToolTemplateUnix('proj').includes('claude-post-tool-use')).toBe(true);
155+
expect(getSqaaPostToolTemplateWindows('proj').includes('claude-post-tool-use')).toBe(true);
156156

157-
expect(getSecretPreToolTemplateUnix().includes('agent-post-tool-use')).toBe(false);
158-
expect(getSecretPromptTemplateUnix().includes('agent-post-tool-use')).toBe(false);
157+
expect(getSecretPreToolTemplateUnix().includes('claude-post-tool-use')).toBe(false);
158+
expect(getSecretPromptTemplateUnix().includes('claude-post-tool-use')).toBe(false);
159159
});
160160
});

tests/unit/pgp-verification.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ import type { PlatformInfo } from '../../src/lib/install-types.js';
3232

3333
const PLATFORM: PlatformInfo = { os: 'linux', arch: 'x86-64', extension: '' };
3434

35-
async function generateKeyPair() {
35+
async function generateKeyPair(): Promise<{ privateKey: string; publicKey: string }> {
3636
return openpgp.generateKey({
3737
type: 'rsa',
3838
rsaBits: 2048,
3939
userIDs: [{ name: 'Test', email: 'test@example.com' }],
40-
});
40+
}) as Promise<{ privateKey: string; publicKey: string }>;
4141
}
4242

4343
async function sign(content: Buffer, armoredPrivateKey: string): Promise<string> {

0 commit comments

Comments
 (0)