- Project Architecture
- Development Workflow
- Testing Guide
- Security Development Guidelines
- Key Files and Their Purposes
- Common Development Tasks
- Troubleshooting Development
- Best Practices
- Additional Resources
-
Extension Entry Point (
src/extension.ts)- Initializes services and providers
- Registers commands and views
- Manages extension lifecycle
- Handles tunnel process lifecycle
-
Services Layer (
src/services/)cloudflaredService.ts: Interfaces with cloudflared CLI- Manages tunnel processes in detached mode
- Handles process cleanup and recovery
- Provides tunnel status monitoring
profileManager.ts: Manages Cloudflare profilesloggingService.ts: Handles logging across componentstokenService.ts: Manages secure token handling and storagetokenAuditService.ts: Tracks and audits token operationsdockerComposeGenerator.ts: Generates Docker configurations- Creates Docker Compose files for tunnels
- Manages environment files for tokens
- Provides Docker networking guidance
-
Views Layer (
src/views/)tunnelTreeView.ts: TreeView for tunnel management- Displays tunnel status with visual indicators
- Provides hover-based tunnel controls
- Handles tunnel selection and actions
- Includes Docker Compose generation button
profilesView.ts: UI for profile management
-
Commands Layer (
src/commands/)- Implements all VS Code commands
- Handles user interactions
- Integrates services with UI
- Manages tunnel lifecycle commands
The extension implements a robust process management system for tunnels:
-
Tunnel Process Management
User Action ↓ Command Handler ↓ CloudflaredService ↓ Detached Process -
Process Features
- Detached mode operation
- Automatic cleanup on shutdown
- Status monitoring and updates
- Error handling and recovery
The logging system is built around component-based logging with file rotation:
~/.vscode/extensions/cloudflare-tunnel/logs/
├── extension.log # Extension lifecycle events
├── tunnel.log # Tunnel operations
├── command.log # Command executions
└── quick_tunnel.log # Quick tunnel operations
Each log type includes:
- Timestamp
- Log level (DEBUG, INFO, WARN, ERROR)
- Component identifier
- Message
- Context data (when relevant)
The extension's UI is built around TreeViews with enhanced functionality:
-
Tunnel TreeView
- Status Indicators
- Green circle: Active tunnel
- Outline circle: Inactive tunnel
- Hover Actions
- Start tunnel button
- Stop tunnel button
- Context Menu
- Copy token
- View info
- Delete tunnel
- Status Indicators
-
Quick Tunnel TreeView
- Status monitoring
- Quick actions
- Port management
The logging system is built around component-based logging with file rotation:
~/.vscode/extensions/cloudflare-tunnel/logs/
├── extension.log # Extension lifecycle events
├── tunnel.log # Tunnel operations
├── command.log # Command executions
└── quick_tunnel.log # Quick tunnel operations
Each log type includes:
- Timestamp
- Log level (DEBUG, INFO, WARN, ERROR)
- Component identifier
- Message
- Context data (when relevant)
Two types of tunnels are supported:
-
Persistent Tunnels
- Created via cloudflared CLI
- Stored in Cloudflare configuration
- Permanent configuration
-
Quick Tunnels
- Created on-demand
- Temporary configuration
- Direct local forwarding
The extension implements a comprehensive security system for handling sensitive data:
-
Token Security
- Secure storage using VSCode's secrets API
- AES-256-GCM encryption for in-memory tokens
- Auto-clearing clipboard after 30 seconds
- Rate limiting and lockout after failed attempts
- Full audit trail of all token operations
-
Token Storage Layers
User Request ↓ TokenService ↓ Memory (Encrypted) ←→ VSCode Secrets -
Security Features
- Encrypted in-memory storage
- Secure clipboard handling
- Rate limiting
- Operation auditing
- Auto-clearing sensitive data
- Warning prompts for sensitive operations
-
Audit System
- Tracks all token operations
- Records timestamps and outcomes
- Monitors failed attempts
- Maintains secure audit logs
- Implements log rotation
The extension includes a Docker Compose generator for containerized tunnel deployment:
-
Component Structure
User Action (Docker button) ↓ Command Handler ↓ DockerComposeGenerator ↓ Generated Files: - docker-compose.{tunnel}.yml - cloudflare.{tunnel}.env -
Security Features
- Token stored in separate environment file
- Environment file named uniquely per tunnel
- Clear documentation for secure usage
-
Configuration Options
- Host machine service connection
- Container service connection
- Network configuration
- Automatic restart handling
-
File Generation
- Workspace-aware file creation
- Untitled file support for no workspace
- Clear usage instructions
- Network configuration examples
-
Prerequisites Installation
npm install npm install -g yo generator-code
-
VS Code Setup
- Install recommended extensions
- Use TypeScript workspace version
- Enable ESLint
-
Development Commands
npm run watch # Start compilation in watch mode npm run lint # Run ESLint npm run test # Run tests
-
Script Organization The project uses a set of standardized scripts for git operations:
scripts/ ├── git-utils.sh # Shared git utilities and functions ├── merge-to-development.sh # Merge current branch to development ├── merge-to-main.sh # Merge current branch to main └── publish.sh # Publish to VS Code MarketplaceKey features of the scripts:
- Consistent error handling and color output
- Shared utility functions
- Test enforcement before merges
- Automatic rollback on failures
- Branch protection
- Clear user feedback
Usage:
# Merge to development ./scripts/merge-to-development.sh # Merge to main ./scripts/merge-to-main.sh # Publish extension ./scripts/publish.sh
-
Adding New Features
- Update DEVELOPMENT_PLAN.md
- Add necessary service methods
- Implement UI components
- Add logging statements
- Update package.json for new commands
-
Modifying Existing Features
- Check existing logs for component behavior
- Update relevant service methods
- Update UI if needed
- Add migration code if needed
-
Local Testing
- Use
F5to launch Extension Development Host - Check logs in Output panel
- Verify all log files are created
- Use
-
Manual Testing Checklist
- Profile creation/switching
- Tunnel operations
- Quick tunnel functionality
- Log rotation
- Error handling
The testing system is built around several layers:
-
Unit Tests (
src/test/unit/)tokenService.test.ts: Tests token security featurestokenAuditService.test.ts: Tests audit functionalityutils.test.ts: Tests utility functions
-
Test Categories
- Security feature testing
- Error handling and recovery
- Rate limiting and lockout
- Audit logging
- Memory management
-
Testing Tools
- Mocha test framework
- Sinon for mocking and stubs
- VSCode test utilities
- Custom test helpers
-
Test Coverage Areas
Security Tests ├── Token Storage │ ├── Secure storage │ ├── Memory encryption │ └── Cleanup ├── Clipboard Handling │ ├── Copy operations │ ├── Auto-clear │ └── Warning prompts ├── Rate Limiting │ ├── Failed attempts │ ├── Lockout periods │ └── Reset conditions └── Audit System ├── Event recording ├── Log rotation └── Query capabilities
The Tunnelfy extension uses the VS Code Extension Testing framework along with Mocha as the test runner. Tests are written in TypeScript and compiled to JavaScript during the test process.
src/test/
├── suite/ # Test suite files
│ ├── extension.test.ts # Main test file for extension
│ ├── tunnels.test.ts # Tunnel management tests
│ ├── cloudflared.test.ts # Cloudflared service tests
│ ├── quickTunnels.test.ts # Quick tunnel tests
│ └── index.ts # Test suite runner configuration
├── runTest.ts # Test runner entry point
└── tsconfig.json # TypeScript config for tests
To run all tests:
npm run testThis command will:
- Clean the test output directory (
npm run clean-tests) - Compile the extension (
npm run compile) - Compile the tests (
npm run compile-tests) - Run the test suite
The following npm scripts are available for testing:
npm run test: Run all testsnpm run clean-tests: Clean the test output directorynpm run compile-tests: Compile test files onlynpm run pretest: Run all pre-test setup (cleaning and compilation)
Create new test files in the src/test/suite/ directory with the .test.ts extension.
Tests use Mocha's testing framework. Here's a basic example:
import * as assert from "assert";
import * as vscode from "vscode";
suite("Your Test Suite Name", () => {
// Run before all tests in the suite
suiteSetup(async () => {
await vscode.commands.executeCommand("workbench.action.closeAllEditors");
});
// Individual test
test("Your Test Name", async () => {
// Your test code here
assert.ok(true);
});
// Run after all tests in the suite
suiteTeardown(() => {
// Cleanup code
});
});-
Isolation: Each test should be independent and not rely on the state from other tests.
-
Async/Await: Use async/await for asynchronous operations:
test("Async test", async () => { const result = await someAsyncOperation(); assert.ok(result); });
-
Cleanup: Use
suiteSetupandsuiteTeardownto handle setup and cleanup. -
Error Handling: Test both success and error cases:
test("Error handling", async () => { try { await functionThatMightFail(); assert.fail("Expected an error"); } catch (error) { assert.ok(error instanceof Error); } });
Tests use a separate TypeScript configuration in src/test/tsconfig.json:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"target": "ES2020",
"outDir": "../../out/test",
"rootDir": "../",
"sourceMap": true
}
}The test runner is configured in src/test/runTest.ts with specific launch arguments:
await runTests({
extensionDevelopmentPath,
extensionTestsPath,
launchArgs: [
"--disable-extensions",
"--disable-gpu",
"--disable-workspace-trust",
],
});- Open the Debug view in VS Code (Cmd+Shift+D)
- Select "Extension Tests" from the dropdown
- Press F5 to start debugging
The tests will run in a new VS Code window, and you can:
- Set breakpoints in your test files
- Step through test execution
- Inspect variables
- Use the Debug Console
-
Tests Not Running:
- Ensure all TypeScript files are compiled
- Run
npm run clean-testsfollowed bynpm test
-
Test Discovery Issues:
- Verify test files end with
.test.ts - Check that test files are in the
src/test/suitedirectory
- Verify test files end with
-
Compilation Errors:
- Run
npm run compile-teststo see detailed errors - Check TypeScript configuration in
src/test/tsconfig.json
- Run
-
VS Code Extension Host Issues:
-
Clear the VS Code extension development host:
rm -rf .vscode-test
-
Run tests again
-
-
Create a new file in
src/test/suite/with the.test.tsextension -
Import required modules:
import * as assert from "assert"; import * as vscode from "vscode";
-
Write your tests using the Mocha framework
-
Run
npm testto verify your tests
Remember to test both positive and negative cases, and ensure your tests are isolated and independent of each other.
-
Token Handling
// Always use TokenService for token operations const token = await tokenService.getTunnelToken(tunnelId); // Never store tokens in plain text // ❌ Bad this.tokens.set(tunnelId, token); // ✅ Good await tokenService.storeTunnelToken(tunnelId, token);
-
Clipboard Operations
// Always use secure clipboard handling // ❌ Bad await vscode.env.clipboard.writeText(token); // ✅ Good const disposable = await tokenService.copyTokenToClipboard(token); context.subscriptions.push(disposable);
-
Audit Logging
// Record all security-relevant operations await auditService.recordEvent({ action: "access", tunnelId, success: true, });
-
Security Testing
- Test all error paths
- Verify encryption
- Check rate limiting
- Validate audit trails
-
Running Tests
# Run all tests npm test # Run specific test suite npm test -- --grep "TokenService" # Run with coverage npm run test:coverage
-
Writing Security Tests
test("Rate limiting after failed attempts", async () => { // Simulate failed attempts for (let i = 0; i < 5; i++) { try { await tokenService.getTunnelToken("non-existent"); } catch (error) { // Expected error } } // Verify lockout await assert.rejects( tokenService.getTunnelToken("valid-id"), /Too many failed attempts/, ); });
cloudflare-vscode/
├── src/
│ ├── extension.ts # Extension entry point
│ ├── services/
│ │ ├── cloudflaredService.ts # Cloudflare CLI integration
│ │ ├── profileManager.ts # Profile management
│ │ ├── loggingService.ts # Logging system
│ │ ├── tokenService.ts # Token management
│ │ └── tokenAuditService.ts # Token audit
│ ├── views/
│ │ ├── tunnelTreeView.ts # Tunnel UI
│ │ └── profilesView.ts # Profile UI
│ └── utils/ # Helper functions
├── _DEV/
│ ├── DEVELOPMENT_PLAN.md # Project roadmap
│ └── DEVELOPMENT_NOTES.md # This file
└── package.json # Extension manifest
-
Add command definition to
package.json:{ "contributes": { "commands": [ { "command": "cloudflare-tunnel.newCommand", "title": "New Command", "category": "Cloudflare" } ] } } -
Register command in
extension.ts:context.subscriptions.push( vscode.commands.registerCommand("cloudflare-tunnel.newCommand", () => { logger.info(LogComponent.COMMAND, "Executing new command"); // Implementation }), );
-
Feature Development
# Create feature branch git checkout -b feature/your-feature # Make changes and commit git add . git commit -m "feat: your feature description" # Merge to development ./scripts/merge-to-development.sh
-
Release Process
# Merge to main ./scripts/merge-to-main.sh # Publish extension ./scripts/publish.sh
-
Add to
LogComponentenum inloggingService.ts:export enum LogComponent { NEW_COMPONENT = "NEW_COMPONENT", }
-
Use in code:
logger.info(LogComponent.NEW_COMPONENT, "Message");
- Update
CloudflaredServicemethods - Add appropriate logging
- Update UI in
TunnelTreeDataProvider - Test with both persistent and quick tunnels
-
Cloudflared CLI Issues
- Check
tunnel.logfor command execution details - Verify environment variables in command execution
- Check certificate paths
- Check
-
UI Update Issues
- Verify TreeView refresh calls
- Check event emitters
- Look for errors in
extension.log
-
Profile Management Issues
- Check profile configuration in
~/.cloudflared/ - Verify file permissions
- Review
command.logfor operation sequence
- Check profile configuration in
- Use VS Code's built-in debugger
- Set breakpoints in service methods
- Monitor log files in real-time
- Use
console.logfor temporary debugging - Check Output panel for immediate feedback
-
Logging
- Log all significant operations
- Include relevant context data
- Use appropriate log levels
- Keep sensitive data out of logs
-
Error Handling
- Log errors with full context
- Provide user-friendly error messages
- Handle cleanup in error cases
- Maintain extension stability
-
Code Organization
- Keep services focused and single-purpose
- Use TypeScript features appropriately
- Follow VS Code extension guidelines
- Maintain clear separation of concerns
-
Testing
- Write tests for new features
- Update existing tests when modifying features
- Test error conditions
- Verify logging behavior