Thank you for your interest in contributing to the SCAN (Sensitive Code Analyzer for Nerds) Gradle Plugin! This document provides guidelines for contributing to the project.
- Code of Conduct
- Getting Started
- Development Environment
- Making Contributions
- Code Standards
- Testing Guidelines
- Documentation
- Pull Request Process
- Issue Reporting
- Community
This project adheres to a Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.
- Java 21 or higher
- Gradle 8.14+ (wrapper included)
- Git for version control
- IDE (IntelliJ IDEA recommended)
- Fork the repository on GitHub
- Clone your fork locally:
git clone https://github.com/theaniketraj/SCAN.git
cd SCAN- Add the upstream remote:
git remote add upstream https://github.com/theaniketraj/SCAN.git- Import the project into your IDE
- Install dependencies:
./gradlew build- Run tests to ensure everything works:
./gradlew testscan-gradle-plugin/
├── src/
│ ├── main/kotlin/com/scan/
│ │ ├── core/ # Core scanning logic
│ │ ├── detectors/ # Pattern and entropy detectors
│ │ ├── filters/ # File filtering logic
│ │ ├── patterns/ # Built-in pattern definitions
│ │ ├── plugin/ # Gradle plugin implementation
│ │ ├── reporting/ # Report generation
│ │ └── utils/ # Utility classes
│ ├── test/kotlin/ # Unit tests
│ └── functionalTest/kotlin/ # Integration tests
├── docs/ # Documentation
├── config/ # Configuration files
└── examples/ # Usage examples# Build the project
./gradlew build
# Run tests
./gradlew test
# Run functional tests
./gradlew functionalTest
# Check code style
./gradlew spotlessCheck
# Fix code style
./gradlew spotlessApply
# Run static analysis
./gradlew detekt
# Generate documentation
./gradlew dokkaHtml
# Publish to local repository (for testing)
./gradlew publishToMavenLocalWe welcome various types of contributions:
- Bug Fixes: Fix issues in existing functionality
- Feature Enhancements: Add new capabilities
- Pattern Additions: Add new secret detection patterns
- Documentation: Improve or expand documentation
- Performance Improvements: Optimize scanning performance
- Test Coverage: Add or improve tests
- Check existing issues to see if your contribution is already being worked on
- Create an issue to discuss major changes before implementing
- Follow the coding standards outlined below
- main: Stable branch, releases are cut from here
- develop: Integration branch for new features
- feature/: Feature branches (e.g.,
feature/new-aws-patterns) - bugfix/: Bug fix branches (e.g.,
bugfix/entropy-calculation) - docs/: Documentation improvements
Create feature branches from develop:
git checkout develop
git pull upstream develop
git checkout -b feature/your-feature-nameWe follow the Kotlin Coding Conventions with some project-specific guidelines:
- Line length: 120 characters maximum
- Indentation: 4 spaces (no tabs)
- Import order: Standard Kotlin import ordering
- Trailing commas: Enabled for multiline constructs
// Classes: PascalCase
class SecretDetector
// Functions and properties: camelCase
fun detectSecrets()
val patternMatches: List<Match>
// Constants: SCREAMING_SNAKE_CASE
const val DEFAULT_ENTROPY_THRESHOLD = 4.5
// File names: PascalCase matching primary class
// SecretDetector.ktUse KDoc for public APIs:
/**
* Detects potential secrets in the given text using pattern matching and entropy analysis.
*
* @param text The text to analyze for secrets
* @param patterns List of regex patterns to apply
* @param entropyThreshold Minimum entropy threshold for random string detection
* @return List of detected secrets with metadata
* @throws IllegalArgumentException if entropy threshold is invalid
*/
fun detectSecrets(
text: String,
patterns: List<Pattern>,
entropyThreshold: Double = DEFAULT_ENTROPY_THRESHOLD
): List<SecretMatch>// Core functionality
package com.scan.core
// Specific detector implementations
package com.scan.detectors.patterns
package com.scan.detectors.entropy
// Gradle plugin components
package com.scan.plugin
// Utilities
package com.scan.utilsUse constructor injection for dependencies:
class SecretScanner(
private val patternDetector: PatternDetector,
private val entropyDetector: EntropyDetector,
private val fileFilter: FileFilter
) {
// Implementation
}// Use specific exception types
class ScanConfigurationException(message: String, cause: Throwable? = null) : Exception(message, cause)
// Handle exceptions appropriately
try {
scanFile(file)
} catch (e: IOException) {
logger.warn("Failed to read file: ${file.absolutePath}", e)
// Continue with other files
} catch (e: ScanConfigurationException) {
logger.error("Configuration error", e)
throw e // Re-throw configuration errors
}Use SLF4J for logging:
class SecretDetector {
companion object {
private val logger = LoggerFactory.getLogger(SecretDetector::class.java)
}
fun detectSecrets(text: String) {
logger.debug("Scanning text of length: ${text.length}")
// Implementation
logger.info("Found ${matches.size} potential secrets")
}
}class SecretDetectorTest {
private val detector = SecretDetector()
@Test
fun `should detect AWS access key`() {
// Given
val text = "aws_access_key_id=AKIAIOSFODNN7EXAMPLE"
// When
val matches = detector.detectSecrets(text)
// Then
assertThat(matches).hasSize(1)
assertThat(matches[0].type).isEqualTo(SecretType.AWS_ACCESS_KEY)
}
}class ScanPluginFunctionalTest {
@Test
fun `should integrate with Gradle build lifecycle`() {
// Given
val projectDir = createTestProject()
addSecretToFile(projectDir, "src/main/kotlin/Config.kt", "API_KEY=secret123")
// When
val result = runGradleTask(projectDir, "build")
// Then
assertThat(result.task(":scanForSecrets")?.outcome).isEqualTo(TaskOutcome.FAILED)
assertThat(result.output).contains("Secret detected in Config.kt")
}
}- Target: 80% line coverage minimum
- Critical paths: 100% coverage for security-critical code
- Edge cases: Test boundary conditions and error scenarios
class PerformanceTest {
@Test
fun `should scan large files efficiently`() {
// Given
val largeFile = generateFile(sizeInMB = 10)
// When
val startTime = System.currentTimeMillis()
val results = scanner.scan(largeFile)
val duration = System.currentTimeMillis() - startTime
// Then
assertThat(duration).isLessThan(5000) // 5 seconds max
}
}- Code Documentation: KDoc comments for public APIs
- User Documentation: Guides and references in
/docs - Examples: Practical usage examples
- Changelog: Record of changes in releases
/**
* Represents a detected secret with metadata about the finding.
*
* @property type The type of secret detected (e.g., AWS_ACCESS_KEY)
* @property content The actual secret content (may be redacted)
* @property file The file where the secret was found
* @property line The line number of the detection
* @property confidence Confidence level of the detection (0.0-1.0)
*/
data class SecretMatch(
val type: SecretType,
val content: String,
val file: File,
val line: Int,
val confidence: Double
)- Clear examples: Provide working code examples
- Step-by-step guides: Break down complex procedures
- Common use cases: Cover typical scenarios
- Troubleshooting: Address common issues
All documentation changes should be reviewed for:
- Accuracy: Information is correct and up-to-date
- Clarity: Content is easy to understand
- Completeness: All necessary information is included
- Examples: Code examples are working and relevant
- Update your branch with the latest changes:
git checkout develop
git pull upstream develop
git checkout your-feature-branch
git rebase develop- Run all checks:
./gradlew build
./gradlew test
./gradlew functionalTest
./gradlew spotlessCheck
./gradlew detekt- Update documentation if needed
type(scope): Brief description
Examples:
feat(patterns): Add support for Slack API tokens
fix(entropy): Correct entropy calculation for Unicode strings
docs(user-guide): Add CI/CD integration examples
## Description
Brief description of the change and why it's needed.
## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
## Testing
- [ ] Unit tests pass
- [ ] Integration tests pass
- [ ] Manual testing performed
## Checklist
- [ ] Code follows the style guidelines
- [ ] Self-review completed
- [ ] Documentation updated
- [ ] Tests added/updated- Automated checks must pass
- Code review by maintainers
- Testing on different environments
- Documentation review if applicable
- Approval by project maintainers
Use the bug report template:
**Describe the bug**
A clear description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Configure plugin with '...'
2. Run gradle task '...'
3. See error
**Expected behavior**
What you expected to happen.
**Environment:**
- OS: [e.g. Windows 10, macOS 12, Ubuntu 20.04]
- Java version: [e.g. OpenJDK 21]
- Gradle version: [e.g. 8.14]
- Plugin version: [e.g. 2.2.0]
**Additional context**
Any other context about the problem.Use the feature request template:
**Is your feature request related to a problem?**
A clear description of what the problem is.
**Describe the solution you'd like**
A clear description of what you want to happen.
**Describe alternatives you've considered**
Alternative solutions or features you've considered.
**Additional context**
Any other context or screenshots about the feature request.- GitHub Discussions: For questions and general discussion
- Issues: For bug reports and feature requests
- Documentation: Check the docs first
Contributors will be recognized in:
- Release notes: Major contributions acknowledged
- Contributors file: All contributors listed
- Special thanks: Outstanding contributions highlighted
Maintainers will:
- Review PRs in a timely manner
- Provide feedback and guidance
- Maintain code quality standards
- Release management and versioning
- Community engagement and support
Thank you for contributing to SCAN! Your efforts help make codebases more secure for everyone. 🔒✨