A GitHub Action that automatically creates and manages Veracode teams based on repository configurations. This action integrates with the Veracode Identity API to ensure teams exist and are properly configured with validated members.
- Automatic Team Management - Create and update Veracode teams seamlessly
- User Validation - Validates all users against Veracode platform before adding to teams
- GitHub Collaborator Sync - Optionally synchronize repository collaborators
- Wildcard Pattern Matching - Support for pattern-based repository mapping
- Incremental Updates - Non-destructive updates that preserve existing members
- Multi-Region Support - Works with US, EU, and Federal Veracode instances
- Comprehensive Error Handling - Retry logic with exponential backoff
- Flexible Configuration - Centralized YAML-based team mapping
- Quick Start
- Usage Examples
- Configuration
- Inputs
- Outputs
- Team Mapping YAML Schema
- Examples
- Troubleshooting
- Requirements
- Contributing
- Create a team mapping file in your configuration repository (default:
veracoderepository):
# team-mapping.yaml
version: '1.0'
mappings:
my-application:
team_name: 'My Application Security Team'
description: 'Security team for my application'
business_unit: 'Engineering'
members:
- user: 'security-admin@example.com'
relationship: 'ADMIN'
- user: 'developer@example.com'
relationship: 'MEMBER'- Add the action to your workflow:
name: Sync Veracode Team
on: [push]
jobs:
sync-team:
runs-on: ubuntu-latest
steps:
- name: Create/Update Veracode Team
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}- name: Create Veracode Team
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}
repository: my-app
owner: my-org- name: Create Veracode Team with Custom Config
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
config-repository: .security-config
config-ref: main
veracode-team-mapping-yaml: teams/mapping.yaml- name: Create Veracode Team (EU)
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID_EU }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY_EU }}
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
veracode-region: EU- name: Create/Update Veracode Team
id: veracode-team
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
- name: Report Results
run: |
echo "Team: ${{ steps.veracode-team.outputs.team-name }}"
echo "Team ID: ${{ steps.veracode-team.outputs.team-id }}"
echo "Action: ${{ steps.veracode-team.outputs.action-taken }}"
echo "Members Added: ${{ steps.veracode-team.outputs.members-added }}"
echo "Members Skipped: ${{ steps.veracode-team.outputs.members-skipped }}"
- name: Handle Skipped Users
if: steps.veracode-team.outputs.members-skipped > 0
run: |
echo "Warning: Some users were not added to the team"
echo "Skipped users: ${{ steps.veracode-team.outputs.skipped-users }}"- name: Create/Update Veracode Team
id: veracode-team
uses: your-org/veracode-create-teams-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}
- name: Create Issue for Skipped Users
if: steps.veracode-team.outputs.members-skipped > 0
uses: actions/github-script@v7
with:
script: |
const skippedUsers = '${{ steps.veracode-team.outputs.skipped-users }}'.split(',')
const body = `
## Veracode Team Sync - Users Not Found
The following users could not be added to the Veracode team:
${skippedUsers.map(u => `- ${u}`).join('
')}
### Action Required
Please ensure these users are invited to the Veracode platform first.
**Team:** ${{ steps.veracode-team.outputs.team-name }}
**Members Added:** ${{ steps.veracode-team.outputs.members-added }}
**Members Skipped:** ${{ steps.veracode-team.outputs.members-skipped }}
`
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Veracode Team Sync: Users Not Found',
body: body,
labels: ['veracode', 'team-management']
})The team mapping configuration file (team-mapping.yaml) defines how
repositories map to Veracode teams.
# team-mapping.yaml
version: '1.0'
# Global default settings (optional)
defaults:
business_unit: 'Engineering'
# Repository-to-Team Mappings
mappings:
# Exact repository name match
my-application:
team_name: 'My Application Security Team'
description: 'Security team for my application'
business_unit: 'Engineering'
members:
- user: 'security-admin@example.com'
relationship: 'ADMIN'
- user: 'developer@example.com'
relationship: 'MEMBER'
# Optional: Sync GitHub collaborators
sync_github_collaborators: true
github_collaborator_filter:
- 'admin'
- 'write'
another-repo:
team_name: 'Another Team'
description: 'Another security team'
members:
- user: 'team-lead@example.com'
relationship: 'ADMIN'
# Wildcard pattern matching
'api-*':
team_name: 'API Services Security Team'
description: 'Team for all API services'
members:
- user: 'api-security@example.com'
relationship: 'ADMIN'
# Fallback configuration (optional)
fallback:
auto_create: true
team_name_template: '{repository_name} Security Team'
default_members:
- user: 'default-admin@example.com'
relationship: 'ADMIN'Root Level:
version(required): Schema version (currently "1.0")defaults(optional): Default settings applied to all teamsmappings(required): Repository-to-team mapping configurationsfallback(optional): Fallback behavior when no mapping matches
Default Settings:
business_unit(optional): Default business unit for all teams
Team Configuration:
team_name(required): Name of the Veracode teamdescription(optional): Team descriptionbusiness_unit(optional): Business unit namemembers(required): Array of team membersuser(required): Email address or usernamerelationship(required): Either "ADMIN" or "MEMBER"
sync_github_collaborators(optional): Sync GitHub collaboratorsgithub_collaborator_filter(optional): Filter collaborators by permission level- Valid values: "admin", "write", "read"
Fallback Configuration:
auto_create(required): Whether to auto-create teamsteam_name_template(optional): Template for team names (supports{repository_name})default_members(optional): Default members for auto-created teams
| Input | Description | Required | Default |
|---|---|---|---|
github-token |
GitHub token with repository access | Yes | - |
veracode-api-id |
Veracode API ID for authentication | Yes | - |
veracode-api-key |
Veracode API Key for authentication | Yes | - |
repository |
GitHub repository name | Yes | - |
owner |
GitHub repository owner | Yes | - |
config-repository |
Repository containing team mapping config | No | veracode |
config-ref |
Branch, tag, or commit SHA for config repository | No | Default branch |
veracode-team-mapping-yaml |
Path to team mapping YAML file | No | team-mapping.yaml |
veracode-region |
Veracode region (US, EU, or FEDERAL) | No | US |
GitHub token used to authenticate with the GitHub API. Requires read access to repositories.
Example:
github-token: ${{ secrets.GITHUB_TOKEN }}Veracode API credentials for HMAC-SHA256 authentication. Store these as GitHub Secrets.
Permissions Required:
Administratorrole
Example:
veracode-api-id: ${{ secrets.VERACODE_API_ID }}
veracode-api-key: ${{ secrets.VERACODE_API_KEY }}The repository name and owner to process. Used to look up the team configuration.
Example:
repository: ${{ github.event.repository.name }}
owner: ${{ github.repository_owner }}The repository containing the team-mapping.yaml configuration file.
Example:
config-repository: security-configThe Veracode instance region. Valid values: US, EU, FEDERAL
Region Endpoints:
US: Commercial US instance (api.veracode.com)EU: European instance (api.veracode.eu)FEDERAL: US Federal instance (api.veracode.us)
Example:
veracode-region: EU| Output | Description | Example |
|---|---|---|
team-id |
UUID of the created/updated team | 550e8400-e29b-41d4-a716-446655440000 |
team-name |
Name of the created/updated team | My Application Security Team |
team-legacy-id |
Legacy ID of the team | 12345 |
action-taken |
Action performed | created or updated or skipped |
member-count |
Total number of members in the team | 5 |
members-added |
Number of members successfully added/validated | 3 |
members-skipped |
Number of members skipped (not found in Veracode) | 2 |
skipped-users |
Comma-separated list of users that were skipped | user1@example.com,user2@example.com |
- name: Create Veracode Team
id: team
uses: your-org/veracode-create-teams-action@v1
with:
# ... inputs ...
- name: Use Outputs
run: |
echo "Team ID: ${{ steps.team.outputs.team-id }}"
echo "Team Name: ${{ steps.team.outputs.team-name }}"# team-mapping.yaml
version: '1.0'
mappings:
web-application:
team_name: 'Web App Security Team'
members:
- user: 'security@example.com'
relationship: 'ADMIN'# team-mapping.yaml
version: '1.0'
defaults:
business_unit: 'Engineering'
mappings:
frontend-app:
team_name: 'Frontend Security Team'
members:
- user: 'frontend-lead@example.com'
relationship: 'ADMIN'
- user: 'frontend-dev@example.com'
relationship: 'MEMBER'
backend-app:
team_name: 'Backend Security Team'
members:
- user: 'backend-lead@example.com'
relationship: 'ADMIN'
- user: 'backend-dev@example.com'
relationship: 'MEMBER'# team-mapping.yaml
version: '1.0'
mappings:
my-repo:
team_name: 'My Repo Security Team'
sync_github_collaborators: true
github_collaborator_filter:
- 'admin'
- 'write'
members:
# Additional members not in GitHub
- user: 'external-security@example.com'
relationship: 'ADMIN'# team-mapping.yaml
version: '1.0'
mappings:
# All API services
'api-*':
team_name: 'API Services Team'
members:
- user: 'api-team@example.com'
relationship: 'ADMIN'
# All microservices
'*-service':
team_name: 'Microservices Team'
members:
- user: 'microservices-team@example.com'
relationship: 'ADMIN'# team-mapping.yaml
version: '1.0'
mappings:
important-app:
team_name: 'Important App Team'
members:
- user: 'team-lead@example.com'
relationship: 'ADMIN'
# Auto-create teams for unmapped repositories
fallback:
auto_create: true
team_name_template: '{repository_name} Security Team'
default_members:
- user: 'default-security@example.com'
relationship: 'ADMIN'Problem: Action reports that users were skipped because they don't exist in Veracode.
Solution:
- Ensure users are invited to the Veracode platform first
- Check that email addresses match exactly
- Verify users have activated their accounts
Example Output:
Warning: 2 users will be skipped (not found or inactive in Veracode)
- newuser@example.com: User does not exist in Veracode platform
- inactive@example.com: User account is inactive
Problem: Action fails with "Failed to fetch file" error.
Solution:
- Verify the
config-repositoryexists and is accessible - Check the
veracode-team-mapping-yamlpath is correct - Ensure the GitHub token has read access to the config repository
Problem: Action fails with 401 or 403 errors.
Solution:
- Verify Veracode API credentials are correct
- Check that credentials have not expired
- Ensure the API user has Team Admin permissions
- Verify the correct region is specified
Problem: Action fails with "No team configuration found for repository".
Solution:
- Add an entry for the repository in the mapping file
- Use wildcard patterns to match multiple repositories
- Configure a fallback auto-create setting
Enable debug logging to get detailed information:
# In repository settings: Settings → Secrets → Actions
# Add secret: ACTIONS_STEP_DEBUG = true- Validate YAML Syntax:
yamllint team-mapping.yaml- Test with Minimal Configuration:
version: '1.0'
mappings:
test-repo:
team_name: 'Test Team'
members:
- user: 'test@example.com'
relationship: 'ADMIN'- Check Action Logs:
- Review info messages about team creation/updates
- Look for warnings about skipped users
- Check for error details in failed runs
- Node.js: 24.0.0 or higher (24.14.0 recommended)
- GitHub Actions: Runner with ubuntu-latest or equivalent
- Veracode API Credentials:
- API ID and API Key
- Administrator permissions (to create teams)
- GitHub Token:
reposcope for reading repository collaborators and content- The default
GITHUB_TOKENprovided by GitHub Actions has sufficient permissions
-
Store credentials as GitHub Secrets:
- Never commit API credentials to the repository
- Use GitHub's encrypted secrets feature
-
Principle of Least Privilege:
- Use API credentials with minimal required permissions
- Limit token scopes to necessary access
-
Audit Logging:
- The action logs all team creation and update operations
- Review action logs regularly for security auditing
Contributions are welcome! Please see our contributing guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
# Clone the repository
git clone https://github.com/your-org/veracode-create-teams-action.git
cd veracode-create-teams-action
# Install dependencies
npm install
# Run tests
npm run test
# Bundle the action
npm run bundle
# Format code
npm run format
# Lint code
npm run lint- Minimum 80% test coverage
- All tests must pass
- Code must pass linting checks
- Follow existing code style and conventions
This project is licensed under the MIT License - see the LICENSE file for details.
If you encounter issues:
- Check the Troubleshooting section
- Review GitHub Issues
- Open a new issue with:
- Full error message
- Sanitized action configuration (no secrets)
- Steps to reproduce
- Expected vs actual behavior