Source Code Portal integrates with multiple external services to provide comprehensive monitoring and status information for your repositories. This page covers all supported integrations and how to configure them.
Supported Integrations:
- Jenkins - Continuous integration and build status
- Snyk - Security vulnerability scanning
- Shields.io - Custom badges and metrics
- GitHub Actions - Workflow status (planned)
All integrations use the Circuit Breaker pattern (Resilience4j) to ensure resilience against service failures and API rate limits.
Monitor CI/CD build status for all repositories in a group.
Jenkins integration provides:
- Real-time build status badges (success, failure, unstable, building)
- Links to Jenkins job pages
- Build history and trends
- Failed test information
Configure Jenkins integration per repository group in config.json:
{
"groupId": "whydah",
"display-name": "Whydah IAM Platform",
"artifactId": ["Whydah*"],
"jenkins": {
"prefix": "Whydah-",
"baseUrl": "https://jenkins.example.com"
}
}Configuration Fields:
-
prefix(required): Jenkins job name prefix- For repository
Whydah-UserAdminService, Jenkins looks for jobWhydah-UserAdminService - Pattern:
{prefix}{repository-name}
- For repository
-
baseUrl(optional): Jenkins server URL- Default: Configured in
application.ymlunderscp.jenkins.base-url - Override per group if you have multiple Jenkins servers
- Default: Configured in
Set the default Jenkins URL in application.yml:
scp:
jenkins:
base-url: https://jenkins.example.comOr via environment variable:
export SCP_JENKINS_BASE_URL=https://jenkins.example.comSCP expects Jenkins jobs to follow this naming pattern:
Pattern: {prefix}{repository-name}
Examples:
- Repository:
Whydah-UserAdminService - Prefix:
Whydah- - Jenkins Job:
Whydah-UserAdminService
Alternatively, use full repository name:
- Repository:
ConfigService - Prefix: (empty or same as repo name)
- Jenkins Job:
ConfigService
The Jenkins badge displays the status of the last build:
Badge States:
- Green: Last build successful
- Yellow: Build unstable (passed with warnings)
- Red: Build failed
- Blue: Build in progress
- Gray: No build information available
Badge Location: Appears on:
- Repository cards on the dashboard
- Group detail page
- Repository detail page
SCP uses the Jenkins REST API to fetch build status:
Endpoint: {baseUrl}/job/{jobName}/lastBuild/api/json
Response Example:
{
"result": "SUCCESS",
"building": false,
"timestamp": 1706450000000,
"url": "https://jenkins.example.com/job/Whydah-UserAdminService/42/"
}Jenkins API calls are protected by a circuit breaker with these settings:
- Failure Threshold: 50% (opens after 50% of calls fail)
- Open State Duration: 60 seconds
- Half-Open Test Requests: 3 requests
- Bulkhead: Max 25 concurrent calls
- Timeout: 75 seconds per call
When Circuit Opens:
- SCP stops making requests to Jenkins
- Badge shows "Unknown" status (gray)
- After 60 seconds, circuit enters "Half-Open" state and tries 3 test requests
- If test requests succeed, circuit closes and normal operation resumes
Issue: Badge shows "Unknown" status
Possible causes:
- Jenkins URL unreachable
- Jenkins job doesn't exist
- Incorrect job name pattern
- Circuit breaker open due to repeated failures
Solutions:
- Verify Jenkins URL:
curl https://jenkins.example.com/api/json - Check job exists: Visit
{baseUrl}/job/{jobName}/ - Review prefix configuration in
config.json - Check circuit breaker status:
/actuator/health
Issue: Badge shows wrong build status
Possible causes:
- Cache not expired
- Jenkins webhook not configured
Solutions:
- Wait for cache expiry (2 minutes) or restart application
- Configure Jenkins webhook to trigger immediate updates
Monitor security vulnerabilities for all repositories in a group.
Snyk integration provides:
- Real-time vulnerability count badges
- Severity levels (high, medium, low)
- Links to Snyk project pages
- Scheduled vulnerability scanning
Configure Snyk integration per repository group in config.json:
{
"groupId": "whydah",
"display-name": "Whydah IAM Platform",
"artifactId": ["Whydah*"],
"snyk": {
"organization": "cantara",
"projectPrefix": "whydah-",
"apiVersion": "2024-01-01"
}
}Configuration Fields:
-
organization(required): Your Snyk organization slug- Find in Snyk URL:
https://app.snyk.io/org/{organization}/projects
- Find in Snyk URL:
-
projectPrefix(optional): Snyk project name prefix- For repository
Whydah-UserAdminService, Snyk looks for projectwhydah-useradminservice - Pattern:
{projectPrefix}{repository-name-lowercase} - If omitted, uses repository name as-is
- For repository
-
apiVersion(optional): Snyk API version- Default:
2024-01-01 - See Snyk API Versioning
- Default:
Set the Snyk API token in application.yml:
scp:
snyk:
api-token: your_snyk_api_token_hereOr via environment variable (recommended):
export SCP_SNYK_API_TOKEN=your_snyk_api_token_hereObtaining a Snyk API Token:
- Log in to Snyk
- Go to Account Settings → General
- Copy your API Token
- Set the
SCP_SNYK_API_TOKENenvironment variable
SCP expects Snyk projects to follow this naming pattern:
Pattern: {projectPrefix}{repository-name-lowercase}
Examples:
- Repository:
Whydah-UserAdminService - Prefix:
whydah- - Snyk Project:
whydah-useradminservice
Case Sensitivity:
- Repository names are converted to lowercase
- Hyphens in repository names are preserved
- Example:
ConfigService-Client→configservice-client
The Snyk badge displays the vulnerability count and severity:
Badge States:
- Green: 0 vulnerabilities
- Yellow: Low/medium severity vulnerabilities
- Orange: High severity vulnerabilities
- Red: Critical severity vulnerabilities
- Gray: No scan data available or scan failed
Badge Location: Appears on:
- Repository cards on the dashboard
- Group detail page
- Repository detail page
SCP uses the Snyk REST API to fetch vulnerability data:
Endpoint: https://api.snyk.io/v1/org/{orgId}/projects
Response Example:
{
"projects": [
{
"name": "whydah-useradminservice",
"issueCountsBySeverity": {
"low": 2,
"medium": 1,
"high": 0,
"critical": 0
}
}
]
}Snyk badges are cached to reduce API calls:
- Cache TTL: 15 minutes
- Refresh Strategy: Scheduled task fetches badges every 15 minutes
- On-Demand Refresh: Snyk webhook (if configured) triggers immediate update
Why Cache?
- Snyk API rate limits (1000 requests/month for free tier)
- Badge rendering is expensive (SVG parsing)
- Vulnerabilities don't change frequently
See Snyk Integration Details for more information on caching strategy.
Snyk API calls are protected by a circuit breaker with the same settings as Jenkins:
- Failure Threshold: 50%
- Open State Duration: 60 seconds
- Bulkhead: Max 25 concurrent calls
- Timeout: 75 seconds per call
Issue: Badge shows "Unknown" status
Possible causes:
- Snyk API token invalid or missing
- Snyk project doesn't exist
- Incorrect project naming pattern
- Rate limit exceeded
Solutions:
- Verify API token:
curl -H "Authorization: token YOUR_TOKEN" https://api.snyk.io/v1/user/me - Check project exists in Snyk dashboard
- Review
projectPrefixconfiguration inconfig.json - Upgrade Snyk plan or reduce API call frequency
Issue: Vulnerabilities not updating
Possible causes:
- Cache not expired
- Snyk scan not run recently
Solutions:
- Wait 15 minutes for cache expiry or restart application
- Trigger Snyk scan manually in Snyk dashboard
Display custom badges for metrics like code coverage, version, license, etc.
Shields.io integration provides:
- Custom badges for any metric
- Static or dynamic badges
- Consistent badge styling
- Support for popular services (Codecov, npm, PyPI, etc.)
Configure Shields.io badges per repository group in config.json:
{
"groupId": "whydah",
"display-name": "Whydah IAM Platform",
"artifactId": ["Whydah*"],
"shields": [
{
"label": "coverage",
"message": "85%",
"color": "brightgreen",
"style": "flat"
},
{
"label": "license",
"message": "Apache 2.0",
"color": "blue"
}
]
}Configuration Fields:
label(required): Badge label (left side)message(required): Badge message (right side)color(required): Badge color (right side)- Options:
brightgreen,green,yellowgreen,yellow,orange,red,blue,lightgrey,gray - Hex colors:
#ff6900
- Options:
style(optional): Badge style- Options:
flat,flat-square,plastic,for-the-badge,social - Default:
flat
- Options:
Use Shields.io's dynamic badge endpoints for live data:
Example: GitHub Release
{
"label": "release",
"message": "dynamic",
"color": "blue",
"url": "https://img.shields.io/github/v/release/Cantara/Whydah-UserAdminService"
}Example: Code Coverage (Codecov)
{
"label": "coverage",
"message": "dynamic",
"color": "brightgreen",
"url": "https://img.shields.io/codecov/c/github/Cantara/Whydah-UserAdminService"
}Example: npm Version
{
"label": "npm",
"message": "dynamic",
"color": "blue",
"url": "https://img.shields.io/npm/v/my-package"
}Shields.io badges are cached to improve performance:
- Static Badges: Cached indefinitely (don't change)
- Dynamic Badges: Cached for 5 minutes
- Refresh Strategy: Badges are refetched when cache expires
Shields.io API calls use a dedicated circuit breaker:
- Failure Threshold: 50%
- Open State Duration: 30 seconds (faster recovery than Jenkins/Snyk)
- Bulkhead: Max 50 concurrent calls (higher than Jenkins/Snyk)
- Timeout: 30 seconds per call (faster than Jenkins/Snyk)
Why Different Settings?
- Shields.io is more reliable than Jenkins/Snyk
- Faster timeout and recovery improve user experience
Issue: Badge not displaying
Possible causes:
- Invalid Shields.io URL
- Network connectivity issues
- Circuit breaker open
Solutions:
- Test badge URL in browser: Visit the
urldirectly - Check network connectivity:
curl https://img.shields.io/badge/test-message-blue - Wait 30 seconds for circuit breaker to recover
Issue: Badge shows wrong data
Possible causes:
- Cache not expired
- Shields.io data source out of date
Solutions:
- Wait 5 minutes for cache expiry
- Check the source service (Codecov, GitHub, npm, etc.)
All external service integrations use the Resilience4j Circuit Breaker pattern to protect against failures.
┌─────────────────────────────────────────────────────┐
│ Circuit States │
├─────────────────────────────────────────────────────┤
│ │
│ CLOSED (Normal Operation) │
│ ┌──────────────────────┐ │
│ │ All requests pass │ │
│ │ through normally │ │
│ └──────┬───────────────┘ │
│ │ │
│ │ >50% failures │
│ ▼ │
│ OPEN (Failing Fast) │
│ ┌──────────────────────┐ │
│ │ All requests fail │ │
│ │ immediately (no API │ │
│ │ calls made) │ │
│ └──────┬───────────────┘ │
│ │ │
│ │ After 60 seconds │
│ ▼ │
│ HALF_OPEN (Testing) │
│ ┌──────────────────────┐ │
│ │ Allow 3 test │ │
│ │ requests through │ │
│ └──────┬───────────────┘ │
│ │ │
│ │ If successful │
│ ▼ │
│ Back to CLOSED │
│ │
└─────────────────────────────────────────────────────┘
Global Settings (all integrations):
- Failure Rate Threshold: 50%
- Slow Call Rate Threshold: 50%
- Slow Call Duration: 30 seconds
- Minimum Number of Calls: 5 (before calculating failure rate)
- Sliding Window Size: 10 calls
- Permitted Calls in Half-Open State: 3
Integration-Specific Settings:
| Integration | Open Duration | Timeout | Bulkhead |
|---|---|---|---|
| Jenkins | 60 seconds | 75s | 25 |
| Snyk | 60 seconds | 75s | 25 |
| Shields.io | 30 seconds | 30s | 50 |
| GitHub | 60 seconds | 75s | 25 |
Check circuit breaker status via Spring Boot Actuator:
Endpoint: /actuator/health
Response Example:
{
"status": "UP",
"components": {
"circuitBreakers": {
"status": "UP",
"details": {
"jenkins": {
"state": "CLOSED",
"failureRate": "10.0%",
"slowCallRate": "5.0%"
},
"snyk": {
"state": "OPEN",
"failureRate": "60.0%",
"slowCallRate": "30.0%"
}
}
}
}
}Interpreting States:
- CLOSED: Normal operation, all systems healthy
- OPEN: Service failing, requests are blocked
- HALF_OPEN: Testing service recovery
- Fail Fast: Don't wait for timeouts when service is down
- Resource Protection: Prevent thread pool exhaustion
- Automatic Recovery: Automatically test service recovery
- Cascading Failure Prevention: Prevent one service failure from taking down the entire application
- Better User Experience: Show cached data or fallback UI instead of hanging
Circuit breakers are implemented in the no.cantara.docsite.commands package:
Key Classes:
BaseResilientCommand- Base class with circuit breaker, bulkhead, timeoutGetJenkinsCommand- Jenkins API callsGetSnykCommand- Snyk API callsGetShieldsCommand- Shields.io API callsGetGitHubCommand- GitHub API calls
Example Usage:
@Service
public class JenkinsService {
public BuildStatus getBuildStatus(String jobName) {
return new GetJenkinsCommand(jobName)
.execute()
.map(this::parseBuildStatus)
.orElse(BuildStatus.UNKNOWN);
}
}To add a new external service integration:
Create a new command class extending BaseResilientCommand:
public class GetNewServiceCommand extends BaseResilientCommand<String> {
private final String resourceUrl;
public GetNewServiceCommand(String resourceUrl) {
super("newservice");
this.resourceUrl = resourceUrl;
}
@Override
protected String run() throws Exception {
// Make HTTP request to external service
HttpResponse<String> response = httpClient.send(
HttpRequest.newBuilder()
.uri(URI.create(resourceUrl))
.GET()
.build(),
HttpResponse.BodyHandlers.ofString()
);
return response.body();
}
@Override
protected String getFallback() {
// Return cached data or default value
return "UNKNOWN";
}
}Add configuration fields to config.json:
{
"groupId": "example",
"newservice": {
"apiKey": "your-api-key",
"projectPrefix": "example-"
}
}Create a service class to interact with the new integration:
@Service
public class NewServiceService {
private final String apiKey;
public NewServiceService(ApplicationProperties properties) {
this.apiKey = properties.getNewService().getApiKey();
}
public ServiceData fetchData(String projectName) {
return new GetNewServiceCommand(buildUrl(projectName))
.execute()
.map(this::parseResponse)
.orElse(ServiceData.UNKNOWN);
}
}Create a custom health indicator for monitoring:
@Component
public class NewServiceHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// Check service connectivity
boolean isUp = checkServiceHealth();
return isUp
? Health.up().build()
: Health.down().withDetail("reason", "Service unreachable").build();
}
}Update this file with configuration and usage instructions for the new integration.
- Snyk Integration Details - Detailed Snyk integration documentation
- Repository Groups - Configure repository groups
- Dashboard - View integration status on dashboard
- Observability - Monitor integration health
- Architecture: Circuit Breaker - Circuit breaker architecture