ggshield is GitGuardian’s CLI tool that helps developers detect and prevent secrets (API keys, passwords, tokens) from being committed to version control systems.
Why is this crucial for Angular & Spring Boot?
- Angular: Often contains API endpoints, authentication tokens, environment variables
- Spring Boot: Database credentials, JWT secrets, external service keys
- Security: Prevents accidental exposure of sensitive data
Big Picture: What Happens When we Use ggshield
1. You write code with secrets (accidentally)
2. You try to commit ? ggshield scans your files
3. ggshield finds secrets ? blocks the commit
4. You fix the secrets ? commit succeeds
Installation & Setup
Method 1: pip (Recommended)
pip install ggshield
Method 2: Docker
docker pull gitguardian/ggshield:latest
Authentication Setup
# Get your API key from GitGuardian dashboard
ggshield auth login
# Or set environment variable
export GITGUARDIAN_API_KEY="your-api-key-here"
Angular Project Configuration
1. Create .gitguardian.yaml
# .gitguardian.yaml
version: 2
paths-ignore:
- node_modules/
- dist/
- coverage/
- .angular/
- e2e/results/
paths-scan:
- src/
- angular.json
- package.json
- tsconfig.json
secret-scan-preference: secret
# Angular-specific exclusions
exclude-secrets:
- generic_api_key:
- "ANGULAR_*" # Angular CLI variables
- "NG_*" # Angular environment variables
The Problem Without Configuration
# Without .gitguardian.yaml, ggshield would scan EVERYTHING:
ggshield secret scan .
#
Scans node_modules/ (thousands of files)
#
Scans build outputs like dist/, target/
#
Finds false positives in minified files
#
Takes 10+ minutes to scan
#
Reports fake secrets from dependencies
How .gitguardian.yaml Solves This
# .gitguardian.yaml - This is ggshield's INSTRUCTION MANUAL
version: 2
#
DON'T scan these folders (saves time, reduces noise)
paths-ignore:
- node_modules/ # Angular dependencies
- dist/ # Angular build output
- target/ # Spring Boot build output
- coverage/ # Test coverage reports
- .angular/ # Angular cache
#
ONLY scan these folders (focus on YOUR code)
paths-scan:
- src/ # Your actual source code
- angular.json # Angular configuration
- application.yml # Spring Boot configuration
#
Ignore known safe "secrets" (reduces false positives)
exclude-secrets:
- generic_api_key:
- "ANGULAR_*" # Angular CLI generates these
- "NG_*" # Angular environment prefixes
- "demo-key-*" # Your demo/test keys
What Happens During Scan
# When you run: ggshield secret scan .
# ggshield reads .gitguardian.yaml and thinks:
1. "Should I scan node_modules/? NO - it's in paths-ignore"
2. "Should I scan src/? YES - it's in paths-scan"
3. "I found 'ANGULAR_CLI_TOKEN=abc123' - but it's in exclude-secrets, so I'll ignore it"
4. "I found 'DATABASE_PASSWORD=realpassword123' - this is NOT excluded, so I'll report it!"
2. Environment File Protection
// src/environments/environment.ts
export const environment = {
production: false,
apiUrl: process.env['API_URL'] || 'http://localhost:8080/api',
// ? DON'T: apiKey: 'sk-1234567890abcdef'
// ? DO: Use environment variables
apiKey: process.env['API_KEY'] || ''
};
3. Angular-specific .gitignore additions
# Environment files
.env
.env.local
.env.*.local
# Angular specific
/dist/
/tmp/
/out-tsc/
/bazel-out/
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
How .gitignore Relates to GitGuardian
# .gitignore tells Git: "Don't track these files"
# .gitguardian.yaml tells ggshield: "Don't scan these files"
# They work TOGETHER for security:
Why We Need BOTH
# .gitignore - Prevents files from being committed
.env # ? Contains real secrets
.env.local # ? Contains real secrets
*.log # ? Might contain sensitive data
node_modules/ # ? Huge, not your code
dist/ # ? Build output, not source
# .DS_Store # ? macOS system files
# Thumbs.db # ? Windows system files
# .gitguardian.yaml - Prevents scanning unnecessary files
paths-ignore:
- node_modules/ # ? Same as .gitignore (performance)
- dist/ # ? Same as .gitignore (performance)
- "*.log" # ? Same as .gitignore (avoid false positives)
Real-World Example
# Without proper .gitignore:
echo "DATABASE_PASSWORD=secret123" > .env
git add .env
git commit -m "Add config"
#
Secret is now in Git history FOREVER!
# With proper .gitignore:
echo "DATABASE_PASSWORD=secret123" > .env
git add .env
#
Git says: "The following paths are ignored by one of your .gitignore files"
# With ggshield + .gitignore:
echo "DATABASE_PASSWORD=secret123" > config.js # Wrong file!
git add config.js
git commit -m "Add config"
#
ggshield says: "Secret detected! Commit blocked!"
Spring Boot Project Configuration
The Problem: Secrets in Code
//
BAD: Secrets directly in code
@RestController
public class UserController {
private String jwtSecret = "my-super-secret-jwt-key-123";
private String dbPassword = "prod-db-password-456";
// This will be detected by ggshield!
}
The Solution: Environment Variables
# application.yml - Spring Boot configuration
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: ${DB_USERNAME:defaultuser} # ? Environment variable
password: ${DB_PASSWORD:defaultpass} # ? Environment variable
security:
jwt:
secret: ${JWT_SECRET:default-dev-secret} # ? Environment variable
//
GOOD: Using Spring's @Value annotation
@RestController
public class UserController {
@Value("${security.jwt.secret}")
private String jwtSecret; // ? Gets value from application.yml
@Value("${spring.datasource.password}")
private String dbPassword; // ? Gets value from application.yml
}
How ggshield Protects This
# .gitguardian.yaml - Configure for Spring Boot
exclude-secrets:
- generic_password:
- "spring.datasource.password" # ? Ignore this pattern in YAML files
- jwt:
- "jwt.secret" # ? Ignore this pattern in YAML files
- generic_api_key:
- "SPRING_*" # ? Ignore Spring environment variables
Complete Workflow Example
# 1. Developer accidentally puts real secret in code
echo 'jwt.secret=prod-jwt-key-abc123' >> application.yml
# 2. Developer tries to commit
git add application.yml
git commit -m "Update JWT config"
# 3. ggshield (via pre-commit hook) scans the file
# 4. ggshield reads .gitguardian.yaml
# 5. ggshield finds 'prod-jwt-key-abc123'
# 6. ggshield checks exclude-secrets - 'jwt.secret' is NOT excluded for REAL values
# 7. ggshield BLOCKS the commit:
SECRET DETECTED!
File: application.yml
Line: 15
Secret: JWT Token (confidence: 95%)
Value: prod-jwt-key-abc123
# 8. Developer fixes it:
echo 'jwt.secret=${JWT_SECRET:dev-secret}' > application.yml
# 9. Developer commits again - SUCCESS! ?
1. Enhanced .gitguardian.yaml for Spring Boot
# .gitguardian.yaml
version: 2
paths-ignore:
- target/
- .mvn/
- node_modules/
- logs/
- *.log
paths-scan:
- src/
- pom.xml
- application*.yml
- application*.properties
# Spring Boot specific exclusions
exclude-secrets:
- generic_password:
- "spring.datasource.password"
- jwt:
- "jwt.secret"
- generic_api_key:
- "SPRING_*"
2. Secure Configuration Management
# application.yml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: ${DB_USERNAME:user}
password: ${DB_PASSWORD:password} # Use environment variables
security:
jwt:
secret: ${JWT_SECRET:default-secret-for-dev}
expiration: 86400000
# application-prod.yml
spring:
datasource:
password: ${DB_PASSWORD} # Must be set via environment
security:
jwt:
secret: ${JWT_SECRET} # Must be set via environment
3. Maven/Gradle Configuration
<!-- pom.xml - Exclude sensitive files from packaging -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/*.key</exclude>
<exclude>**/*.p12</exclude>
<exclude>**/*.jks</exclude>
</excludes>
</resource>
</resources>
</build>
Pre-commit Hooks Setup
1. Install pre-commit
pip install pre-commit
2. Create .pre-commit-config.yaml
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitguardian/ggshield
rev: v1.25.0
hooks:
- id: ggshield
name: GitGuardian Shield
entry: ggshield secret scan pre-commit
language: python
stages: [commit]
types: [text]
# Additional hooks for Angular/Spring Boot
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-json
- id: check-yaml
# Angular specific
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v8.44.0
hooks:
- id: eslint
files: \.(js|ts)$
types: [file]
3. Install and activate
pre-commit install
pre-commit run --all-files # Test on all files
The Magic Behind the Scenes
# When you install pre-commit hooks:
pre-commit install
# This creates: .git/hooks/pre-commit
# Every time you run 'git commit', this script runs FIRST
What Happens During Commit
# You type: git commit -m "Add new feature"
# Git automatically runs:
1. .git/hooks/pre-commit
2. pre-commit runs all hooks from .pre-commit-config.yaml
3. ggshield secret scan pre-commit
4. ggshield reads .gitguardian.yaml for configuration
5. ggshield scans only the files you're trying to commit
6. If secrets found: BLOCK commit
If no secrets: Allow commit
Visual Example
# Normal commit without ggshield:
git add file-with-secret.js
git commit -m "Add feature"
#
Commit succeeds (BAD!)
# Commit with ggshield pre-commit hook:
git add file-with-secret.js
git commit -m "Add feature"
# ggshield runs automatically:
Scanning staged files...
Secret detected in file-with-secret.js
Commit blocked!
# Fix the secret:
# Remove secret from file-with-secret.js
git add file-with-secret.js
git commit -m "Add feature"
#
Commit succeeds (GOOD!)
CI/CD Integration
GitHub Actions Example
# .github/workflows/security-scan.yml
name: Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Full history for better scanning
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install ggshield
run: pip install ggshield
- name: Scan for secrets
env:
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
run: ggshield secret scan ci
# Angular specific steps
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Angular dependencies
run: npm ci
- name: Angular Security Audit
run: npm audit --audit-level moderate
# Spring Boot specific steps
- name: Setup Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Maven Security Check
run: mvn org.owasp:dependency-check-maven:check
GitLab CI Example
# .gitlab-ci.yml
stages:
- security
- build
- test
security-scan:
stage: security
image: python:3.9
before_script:
- pip install ggshield
script:
- ggshield secret scan ci
variables:
GITGUARDIAN_API_KEY: $GITGUARDIAN_API_KEY
only:
- merge_requests
- main
- develop
Project Structure

- Step 1: .gitignore protects sensitive files
- .gitguardian.yaml configures scanning
- .pre-commit-config.yaml sets up automatic scanning

- Step 4: Safe configuration files

- Step 5: Environment template

- Step 6: Real environment file


Best Practices
1. Development Workflow
# Daily workflow
git add .
git commit -m "feat: add user authentication"
# ggshield automatically scans via pre-commit hook
# Manual scan before push
ggshield secret scan repo .
# Scan specific files
ggshield secret scan path src/environments/
2. Environment Management
# .env.example (commit this)
API_URL=http://localhost:8080/api
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp
JWT_SECRET=your-jwt-secret-here
GITGUARDIAN_API_KEY=your-api-key-here
# .env (never commit this)
API_URL=https://api.production.com
DB_HOST=prod-db.company.com
DB_PORT=5432
DB_NAME=prod_myapp
JWT_SECRET=actual-production-secret
GITGUARDIAN_API_KEY=actual-api-key
3. Team Configuration
# .gitguardian.yaml - Team settings
version: 2
verbose: true
show-secrets: false # Don't show actual secrets in output
# Custom rules for your team
exclude-secrets:
- generic_api_key:
- "DEMO_*" # Demo/test keys
- "MOCK_*" # Mock data
- "TEST_*" # Test environment
# Incident management
on-secret-found:
- webhook: "https://your-team-webhook.com/security-alert"
- email: "security-team@company.com"
Troubleshooting
Common Issues & Solutions
1. False Positives
# Add to .gitguardian.yaml
exclude-secrets:
- generic_api_key:
- "example-key-123" # Known safe example
- "demo-token-*" # Demo patterns
2. Large Repository Scanning
# Scan only recent commits
ggshield secret scan ci --max-commits-for-hook 10
# Scan specific branch
ggshield secret scan repo --branch feature/new-auth
3. Performance Issues
# .gitguardian.yaml - Optimize performance
paths-ignore:
- "**/*.min.js" # Minified files
- "**/*.bundle.js" # Bundled files
- "**/node_modules/" # Dependencies
- "**/target/" # Build artifacts
- "**/*.log" # Log files
4. Integration Issues
# Debug mode
ggshield --debug secret scan path .
# Check configuration
ggshield config list
# Test API connection
ggshield api-status
Monitoring & Reporting
1. Dashboard Integration
- Access GitGuardian dashboard for incident tracking
- Set up team notifications
- Monitor scan statistics
2. Custom Reporting
# Generate scan report
ggshield secret scan repo . --json > security-report.json
# Integrate with monitoring tools
ggshield secret scan ci --output sarif > results.sarif
Summary
By implementing ggshield in our Angular and Spring Boot development workflow, we:
Prevent secret leaks before they reach version control
Automate security scanning in CI/CD pipelines
Maintain clean commit history without sensitive data
Comply with security best practices
Protect our applications and infrastructure
Remember: Security is not a one-time setup but an ongoing process. Regularly update our configurations and stay informed about new security practices! ?