Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f84414d
refactor: modularize claude-executor and extract shared utilities
ajmallesh Jan 12, 2026
49e53b9
feat: add Claude Code custom commands for debug and review
ajmallesh Jan 12, 2026
6fdfdcb
feat: add Temporal integration foundation (phase 1-2)
ajmallesh Jan 12, 2026
322e427
feat: add Temporal activities for agent execution (phase 3)
ajmallesh Jan 12, 2026
eb7eced
feat: add Temporal workflow for 5-phase pipeline orchestration (phase 4)
ajmallesh Jan 12, 2026
05f8e23
feat: add Temporal worker, client, and query tools (phase 5)
ajmallesh Jan 12, 2026
cbb2b4a
feat: fix Docker worker container setup
ajmallesh Jan 12, 2026
b26c690
fix: add report assembly step to Temporal workflow
ajmallesh Jan 12, 2026
5bda6fa
refactor: consolidate Docker setup to root docker-compose.yml
ajmallesh Jan 12, 2026
b84c1d3
feat: improve Temporal client UX and env handling
ajmallesh Jan 13, 2026
69f2d8f
refactor: simplify session ID handling and improve Taskfile options
ajmallesh Jan 13, 2026
4de1508
chore: add .env.example and simplify .gitignore
ajmallesh Jan 13, 2026
1f303b0
docs: update README and CLAUDE.md for Temporal workflow usage
ajmallesh Jan 13, 2026
89cc30b
refactor: replace Taskfile with bash CLI script
ajmallesh Jan 13, 2026
e521e98
docs: fix deliverable filename in README
ajmallesh Jan 13, 2026
50629a2
refactor: remove direct CLI and .shannon-store.json in favor of Temporal
ajmallesh Jan 13, 2026
65b9bc4
chore: remove licensing comments from prompt files to prevent leaking…
ajmallesh Jan 13, 2026
c12eca0
fix: resolve parallel workflow race conditions and retry logic bugs
ajmallesh Jan 13, 2026
eaff84b
refactor: pipeline vuln→exploit workflow for parallel execution
ajmallesh Jan 13, 2026
3b391ec
fix: re-throw retryable errors in checkExploitationQueue
ajmallesh Jan 13, 2026
eb8ab3b
feat: add PostHog telemetry with persistent installation tracking
ajmallesh Jan 14, 2026
636ae6f
docs: update telemetry instructions
ajmallesh Jan 14, 2026
7dc8cfe
fix: remove pipeline_testing_mode from telemetry events
ajmallesh Jan 14, 2026
f3cb5dc
Merge branch 'main' into feat/telemetry
ajmallesh Jan 15, 2026
9d69e43
fix: resolve merge artifacts from main branch integration
ajmallesh Jan 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Shannon is available in two editions:
- [Architecture](#-architecture)
- [Coverage and Roadmap](#-coverage-and-roadmap)
- [Disclaimers](#-disclaimers)
- [Telemetry](#-telemetry)
- [License](#-license)
- [Community & Support](#-community--support)
- [Get in Touch](#-get-in-touch)
Expand Down Expand Up @@ -437,6 +438,38 @@ Shannon is designed for legitimate security auditing purposes only.
Windows Defender may flag files in `xben-benchmark-results/` or `deliverables/` as malware. These are false positives caused by exploit code in the reports. Add an exclusion for the Shannon directory in Windows Defender, or use Docker/WSL2.


## 📊 Telemetry

Shannon collects anonymous usage telemetry to help improve the tool.

### What We Collect

- Workflow and agent lifecycle events (start, complete, fail)
- Timing and cost metrics (duration, API costs)
- Error types (NOT error messages or stack traces)

### What We DO NOT Collect

- Target URLs, repository paths, or configuration
- Vulnerability findings or security reports
- Error messages, stack traces, or debugging info
- Any personally identifiable information (PII)

### Opting Out

Telemetry is enabled by default. To disable it, set one of:

```bash
# Standard opt-out
export DO_NOT_TRACK=1

# Shannon-specific opt-out
export SHANNON_TELEMETRY=off
```

Or add `DO_NOT_TRACK=1` to your `.env` file.


## 📜 License

Shannon Lite is released under the [GNU Affero General Public License v3.0 (AGPL-3.0)](LICENSE).
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ services:
- ./audit-logs:/app/audit-logs
- ${TARGET_REPO:-.}:/target-repo
- ${BENCHMARKS_BASE:-.}:/benchmarks
- ${HOME}/.shannon:/tmp/.shannon
shm_size: 2gb
ipc: host
security_opt:
Expand Down
90 changes: 87 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"figlet": "^1.9.3",
"gradient-string": "^3.0.0",
"js-yaml": "^4.1.0",
"posthog-node": "^5.20.0",
"zod": "^3.22.4",
"zx": "^8.0.0"
},
Expand Down
26 changes: 26 additions & 0 deletions src/telemetry/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2025 Keygraph, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3
// as published by the Free Software Foundation.

/**
* Telemetry Module - Public API
*
* Usage:
* import { telemetry, TelemetryEvent } from '../telemetry/index.js';
*
* telemetry.initialize();
* telemetry.track(TelemetryEvent.WORKFLOW_START, { has_config: true });
* await telemetry.shutdown();
*/

export { telemetry, hashTargetUrl } from './telemetry-manager.js';
export { TelemetryEvent } from './telemetry-events.js';
export { getInstallationId } from './installation-id.js';
export type {
BaseTelemetryProperties,
AgentEventProperties,
WorkflowEventProperties,
} from './telemetry-events.js';
export { loadTelemetryConfig } from './telemetry-config.js';
78 changes: 78 additions & 0 deletions src/telemetry/installation-id.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (C) 2025 Keygraph, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3
// as published by the Free Software Foundation.

/**
* Installation ID - Persistent anonymous identifier for telemetry.
*
* Generates a UUID and persists it to ~/.shannon/telemetry-id
* On subsequent runs, reads the existing ID from the file.
* Handles errors gracefully by returning a random UUID.
*/

import { randomUUID } from 'crypto';
import { readFile, writeFile, mkdir } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';

const SHANNON_DIR = '.shannon';
const TELEMETRY_ID_FILE = 'telemetry-id';

/**
* Get the path to the telemetry ID file.
* Returns ~/.shannon/telemetry-id
*/
function getTelemetryIdPath(): string {
return join(homedir(), SHANNON_DIR, TELEMETRY_ID_FILE);
}

/**
* Get the path to the Shannon config directory.
* Returns ~/.shannon
*/
function getShannonDir(): string {
return join(homedir(), SHANNON_DIR);
}

/**
* Get or create a persistent installation ID.
*
* - If ~/.shannon/telemetry-id exists, reads and returns the ID
* - If not, generates a new UUID, persists it, and returns it
* - On any error, returns a random UUID (doesn't persist)
*
* @returns Promise<string> - The installation ID (UUID format)
*/
export async function getInstallationId(): Promise<string> {
const filePath = getTelemetryIdPath();

try {
// Try to read existing ID
const existingId = await readFile(filePath, 'utf-8');
const trimmedId = existingId.trim();

// Validate it looks like a UUID (basic check)
if (trimmedId.length >= 32) {
return trimmedId;
}
} catch {
// File doesn't exist or can't be read - will create new ID
}

// Generate new ID
const newId = randomUUID();

try {
// Ensure ~/.shannon directory exists
await mkdir(getShannonDir(), { recursive: true });

// Persist the new ID
await writeFile(filePath, newId, 'utf-8');
} catch {
// Failed to persist - return the ID anyway (won't be persistent)
}

return newId;
}
68 changes: 68 additions & 0 deletions src/telemetry/telemetry-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2025 Keygraph, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License version 3
// as published by the Free Software Foundation.

/**
* Telemetry configuration with opt-out support.
*
* Telemetry is enabled by default. Users can disable via:
* - DO_NOT_TRACK=1 (standard convention: https://consoledonottrack.com/)
* - SHANNON_TELEMETRY=off|false|0
*/

export interface TelemetryConfig {
enabled: boolean;
apiKey: string;
host: string;
}

// PostHog project configuration
// This is a write-only key - safe to publish, users cannot read analytics
const POSTHOG_API_KEY = 'phc_9EF2G6mm83rfLef5WmVLiNSyGQ4x0p8NzTRKiEAgvD4';
const POSTHOG_HOST = 'https://us.i.posthog.com';

/**
* Check if telemetry is enabled based on environment variables.
*/
function isTelemetryEnabled(): boolean {
// Standard opt-out: DO_NOT_TRACK
const doNotTrack = process.env.DO_NOT_TRACK;
if (doNotTrack === '1' || doNotTrack?.toLowerCase() === 'true') {
return false;
}

// Shannon-specific opt-out
const shannonTelemetry = process.env.SHANNON_TELEMETRY?.toLowerCase();
if (
shannonTelemetry === 'off' ||
shannonTelemetry === 'false' ||
shannonTelemetry === '0'
) {
return false;
}

return true;
}

/**
* Load telemetry configuration from environment.
* Never throws - returns disabled config on any error.
*/
export function loadTelemetryConfig(): TelemetryConfig {
try {
return {
enabled: isTelemetryEnabled(),
apiKey: POSTHOG_API_KEY,
host: POSTHOG_HOST,
};
} catch {
// Config loading should never fail - return disabled
return {
enabled: false,
apiKey: POSTHOG_API_KEY,
host: POSTHOG_HOST,
};
}
}
Loading