Use Case Overview
GitHub credential attestations transform code contributions into verifiable digital assets that follow developers across platforms. Create meritocratic systems based on actual contribution history rather than self-reported skills. Ideal For:- Developer community platforms
- Bounty and grants programs
- Technical hiring and recruitment
- Open source contribution tracking
- Developer reputation systems
- Hackathon team formation
Implementation
Schema Configuration
Define GitHub contribution attestation schemas:Copy
// Basic GitHub profile verification
const githubProfileSchema = 'github-profile-v1';
// Definition: username:string,verified:bool,publicRepos:uint16,followers:uint16,totalCommits:uint32,accountAge:uint32,timestamp:uint64
// Repository contribution tracking
const repoContributionSchema = 'github-repo-contribution-v1';
// Definition: username:string,repoName:string,commits:uint16,additions:uint32,deletions:uint32,pullRequests:uint16,issues:uint16,timestamp:uint64
// Skill verification based on code analysis
const skillVerificationSchema = 'github-skill-verification-v1';
// Definition: username:string,language:string,linesOfCode:uint32,repositories:uint16,complexity:uint8,recentActivity:bool,timestamp:uint64
// Open source maintainer credentials
const maintainerSchema = 'github-maintainer-v1';
// Definition: username:string,repoName:string,role:string,stars:uint16,forks:uint16,contributors:uint16,maintainerSince:uint64,timestamp:uint64
GitHub Oracle Authority
Implement automated GitHub data verification:Copy
import { StellarAttestSDK, SolanaAttestSDK } from '@attestprotocol/sdk';
import { Octokit } from '@octokit/rest';
class GitHubCredentialOracle {
private sdk: StellarAttestSDK | SolanaAttestSDK;
private github: Octokit;
private rateLimiter: RateLimiter;
constructor(
sdk: StellarAttestSDK | SolanaAttestSDK,
githubToken: string
) {
this.sdk = sdk;
this.github = new Octokit({ auth: githubToken });
this.rateLimiter = new RateLimiter({ tokensPerInterval: 5000, interval: 'hour' });
}
Copy
async verifyAndAttestGitHubProfile(
userAddress: string,
githubUsername: string,
verificationProof: string
): Promise<GitHubVerificationResult> {
const sessionId = `github-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
try {
// Step 1: Verify the user owns the GitHub account
await this.verifyAccountOwnership(githubUsername, verificationProof, userAddress);
// Step 2: Gather comprehensive GitHub data
const analysisResults = await this.performGitHubAnalysis(githubUsername);
// Step 3: Create all attestations
const attestations = await this.createAllAttestations(
userAddress,
githubUsername,
analysisResults,
sessionId
);
return {
success: true,
sessionId,
...attestations,
profileData: analysisResults.profileData,
expiresAt: Date.now() + (90 * 24 * 60 * 60 * 1000) // 90 days
};
} catch (error) {
await this.logVerificationError(sessionId, githubUsername, error);
throw error;
}
}
Copy
private async performGitHubAnalysis(githubUsername: string) {
// Gather all GitHub data in parallel for efficiency
const [profileData, contributionData, skillData] = await Promise.all([
this.gatherProfileData(githubUsername),
this.analyzeContributions(githubUsername),
this.analyzeSkills(githubUsername)
]);
return { profileData, contributionData, skillData };
}
Copy
private async createAllAttestations(
userAddress: string,
githubUsername: string,
analysisResults: any,
sessionId: string
) {
// Create profile attestation
const profileAttestation = await this.createProfileAttestation(
userAddress, githubUsername, analysisResults, sessionId
);
// Create skill attestations in parallel
const [skillAttestations, repoAttestations] = await Promise.all([
this.createSkillAttestations(userAddress, githubUsername, analysisResults.skillData, sessionId),
this.createRepositoryAttestations(userAddress, githubUsername, analysisResults.contributionData.repositories, sessionId)
]);
return {
profileAttestation: profileAttestation,
skillAttestations,
repoAttestations
};
}
Copy
private async createProfileAttestation(
userAddress: string,
githubUsername: string,
analysisResults: any,
sessionId: string
): Promise<string> {
const { profileData, contributionData } = analysisResults;
// Create structured profile attestation value
const profileValue = [
`username:${githubUsername}`,
`verified:true`,
`publicRepos:${profileData.publicRepos}`,
`followers:${profileData.followers}`,
`totalCommits:${contributionData.totalCommits}`,
`accountAge:${profileData.accountAge}`,
`timestamp:${Math.floor(Date.now() / 1000)}`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'github-profile-v1',
subject: userAddress,
value: profileValue,
reference: sessionId
});
if (attestation.error) {
throw new Error(`Profile attestation failed: ${attestation.error}`);
}
return attestation.data;
}
}
**Account Ownership Verification**
```typescript
private async verifyAccountOwnership(
username: string,
proof: string,
walletAddress: string
): Promise<boolean> {
try {
// Support multiple verification methods
if (proof.startsWith('gist:')) {
return await this.verifyGistOwnership(username, proof, walletAddress);
}
if (proof.startsWith('commit:')) {
return await this.verifyCommitOwnership(username, proof, walletAddress);
}
throw new Error('Unsupported verification method');
} catch (error) {
console.error('Ownership verification failed:', error);
return false;
}
}
Copy
private async verifyGistOwnership(
username: string,
proof: string,
walletAddress: string
): Promise<boolean> {
const gistId = proof.replace('gist:', '');
// Fetch the gist from GitHub
const gist = await this.github.gists.get({ gist_id: gistId });
// Verify gist owner matches claimed username
if (gist.data.owner?.login !== username) {
console.log('Gist owner mismatch');
return false;
}
// Check if any gist file contains the wallet address
const gistFiles = Object.values(gist.data.files || {});
const hasWalletAddress = gistFiles.some(file =>
file?.content?.includes(walletAddress)
);
return hasWalletAddress;
}
Copy
private async verifyCommitOwnership(
username: string,
proof: string,
walletAddress: string
): Promise<boolean> {
const [, repo, sha] = proof.split(':');
// Fetch the specific commit
const commit = await this.github.repos.getCommit({
owner: username,
repo,
ref: sha
});
// Verify commit message contains wallet address
const commitMessage = commit.data.commit.message;
return commitMessage.includes(walletAddress);
}
}
**Profile Data Collection**
```typescript
private async gatherProfileData(username: string): Promise<GitHubProfileData> {
// Rate limit protection
await this.rateLimiter.removeTokens(1);
// Fetch user profile and repositories in parallel
const [profile, repos] = await Promise.all([
this.github.users.getByUsername({ username }),
this.github.repos.listForUser({
username,
type: 'owner',
sort: 'updated',
per_page: 100
})
]);
// Calculate account age in days
const accountAge = Math.floor(
(Date.now() - new Date(profile.data.created_at).getTime()) / (24 * 60 * 60 * 1000)
);
return {
username,
publicRepos: profile.data.public_repos,
followers: profile.data.followers,
following: profile.data.following,
accountAge,
repositories: repos.data,
bio: profile.data.bio,
company: profile.data.company,
location: profile.data.location
};
}
}
Copy
private async analyzeContributions(username: string): Promise<ContributionAnalysis> {
await this.rateLimiter.removeTokens(2);
// Get user's repositories
const repos = await this.github.repos.listForUser({
username,
type: 'owner',
per_page: 100
});
// Initialize tracking variables
const analysisData = this.initializeAnalysisData();
// Analyze top 20 repositories (to stay within rate limits)
const topRepos = repos.data.slice(0, 20);
const repoAnalyses = await this.analyzeRepositoriesBatch(username, topRepos);
// Aggregate results
return this.aggregateContributionData(repoAnalyses, analysisData);
}
Copy
private initializeAnalysisData() {
return {
totalCommits: 0,
totalAdditions: 0,
totalDeletions: 0,
languageStats: {} as Record<string, number>,
repositoryContributions: [] as RepositoryContribution[]
};
}
Copy
private async analyzeRepositoriesBatch(username: string, repos: any[]) {
const repoAnalyses = [];
// Process repositories sequentially to respect rate limits
for (const repo of repos) {
try {
const analysis = await this.analyzeSingleRepository(username, repo);
repoAnalyses.push(analysis);
} catch (error) {
console.warn(`Failed to analyze repo ${repo.name}:`, error);
// Continue with other repositories
}
}
return repoAnalyses;
}
Copy
private async analyzeSingleRepository(username: string, repo: any) {
await this.rateLimiter.removeTokens(1);
// Get commits for this repository
const commits = await this.github.repos.listCommits({
owner: username,
repo: repo.name,
author: username,
per_page: 100
});
const repoCommits = commits.data.length;
return {
name: repo.name,
commits: repoCommits,
stars: repo.stargazers_count,
forks: repo.forks_count,
language: repo.language,
lastUpdated: new Date(repo.updated_at).getTime()
};
}
Copy
private aggregateContributionData(repoAnalyses: any[], analysisData: any): ContributionAnalysis {
let totalCommits = 0;
const languageStats: Record<string, number> = {};
// Process each repository's analysis
for (const repoAnalysis of repoAnalyses) {
totalCommits += repoAnalysis.commits;
// Track language usage by commit count
if (repoAnalysis.language) {
languageStats[repoAnalysis.language] =
(languageStats[repoAnalysis.language] || 0) + repoAnalysis.commits;
}
analysisData.repositoryContributions.push(repoAnalysis);
}
// Determine primary languages (top 5 by commits)
const primaryLanguages = Object.entries(languageStats)
.sort(([,a], [,b]) => b - a)
.slice(0, 5)
.map(([lang]) => lang);
return {
totalCommits,
totalAdditions: 0, // Placeholder - would require additional API calls
totalDeletions: 0, // Placeholder - would require additional API calls
languageStats,
repositories: analysisData.repositoryContributions,
primaryLanguages
};
}
}
Copy
private async analyzeSkills(username: string): Promise<SkillAnalysis> {
// Use repository language data as proxy for skill analysis
// In production, this would integrate with code analysis tools
const contributions = await this.analyzeContributions(username);
// Map languages to skill objects with proficiency levels
const skills = Object.entries(contributions.languageStats).map(([language, commits]) => ({
skill: language,
level: this.calculateSkillLevel(commits),
repositories: contributions.repositories.filter(r => r.language === language).length,
totalCommits: commits,
recentActivity: this.hasRecentActivity(contributions.repositories, language)
}));
return {
skills,
overallLevel: this.calculateOverallLevel(skills),
specializations: skills.filter(s => s.level >= 7).map(s => s.skill)
};
}
Copy
private calculateSkillLevel(commits: number): number {
// Map commit count to skill proficiency levels
if (commits >= 1000) return 10; // Expert
if (commits >= 500) return 8; // Advanced
if (commits >= 200) return 6; // Intermediate
if (commits >= 50) return 4; // Beginner
return 2; // Novice
}
private calculateOverallLevel(skills: SkillData[]): number {
if (skills.length === 0) return 0;
const totalScore = skills.reduce((sum, skill) => sum + skill.level, 0);
return Math.round(totalScore / skills.length);
}
Copy
private hasRecentActivity(repositories: RepositoryContribution[], language: string): boolean {
const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);
return repositories
.filter(r => r.language === language)
.some(r => r.lastUpdated > thirtyDaysAgo);
}
}
Copy
private async createSkillAttestations(
userAddress: string,
username: string,
skillData: SkillAnalysis,
sessionId: string
): Promise<string[]> {
const attestations: string[] = [];
// Filter skills with reasonable proficiency (level 4+)
const qualifiedSkills = skillData.skills.filter(skill => skill.level >= 4);
// Create attestations for each qualified skill
for (const skill of qualifiedSkills) {
try {
const attestationUID = await this.createSingleSkillAttestation(
userAddress, username, skill, sessionId
);
if (attestationUID) {
attestations.push(attestationUID);
}
} catch (error) {
console.warn(`Failed to create skill attestation for ${skill.skill}:`, error);
// Continue with other skills
}
}
return attestations;
}
Copy
private async createSingleSkillAttestation(
userAddress: string,
username: string,
skill: SkillData,
sessionId: string
): Promise<string | null> {
// Estimate lines of code (rough approximation)
const estimatedLOC = skill.totalCommits * 50;
// Create structured skill attestation value
const skillValue = [
`username:${username}`,
`language:${skill.skill}`,
`linesOfCode:${estimatedLOC}`,
`repositories:${skill.repositories}`,
`complexity:${skill.level}`,
`recentActivity:${skill.recentActivity}`,
`timestamp:${Math.floor(Date.now() / 1000)}`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'github-skill-verification-v1',
subject: userAddress,
value: skillValue,
reference: `${sessionId}-skill-${skill.skill}`
});
return attestation.error ? null : attestation.data;
}
}
Copy
private async createRepositoryAttestations(
userAddress: string,
username: string,
repositories: RepositoryContribution[],
sessionId: string
): Promise<string[]> {
// Select top repositories by impact (stars + commits)
const topRepos = this.selectTopRepositories(repositories, 10);
const attestations: string[] = [];
// Create attestations for each top repository
for (const repo of topRepos) {
try {
const attestationUID = await this.createSingleRepoAttestation(
userAddress, username, repo, sessionId
);
if (attestationUID) {
attestations.push(attestationUID);
}
} catch (error) {
console.warn(`Failed to create repo attestation for ${repo.name}:`, error);
}
}
return attestations;
}
Copy
private selectTopRepositories(repositories: RepositoryContribution[], limit: number) {
return repositories
.sort((a, b) => {
// Score based on stars and commits
const scoreA = a.stars + a.commits;
const scoreB = b.stars + b.commits;
return scoreB - scoreA;
})
.slice(0, limit);
}
Copy
private async createSingleRepoAttestation(
userAddress: string,
username: string,
repo: RepositoryContribution,
sessionId: string
): Promise<string | null> {
// Create structured repository attestation value
const repoValue = [
`username:${username}`,
`repoName:${repo.name}`,
`commits:${repo.commits}`,
`additions:0`, // Placeholder - would require additional API calls
`deletions:0`, // Placeholder - would require additional API calls
`pullRequests:0`, // Placeholder - would require additional API calls
`issues:0`, // Placeholder - would require additional API calls
`timestamp:${Math.floor(Date.now() / 1000)}`
].join(',');
const attestation = await this.sdk.attest({
schemaUID: 'github-repo-contribution-v1',
subject: userAddress,
value: repoValue,
reference: `${sessionId}-repo-${repo.name}`
});
return attestation.error ? null : attestation.data;
}
}
Copy
interface GitHubProfileData {
username: string;
publicRepos: number;
followers: number;
following: number;
accountAge: number;
repositories: any[];
bio: string | null;
company: string | null;
location: string | null;
}
interface ContributionAnalysis {
totalCommits: number;
totalAdditions: number;
totalDeletions: number;
languageStats: Record<string, number>;
repositories: RepositoryContribution[];
primaryLanguages: string[];
}
interface RepositoryContribution {
name: string;
commits: number;
stars: number;
forks: number;
language: string | null;
lastUpdated: number;
}
interface SkillAnalysis {
skills: SkillData[];
overallLevel: number;
specializations: string[];
}
interface SkillData {
skill: string;
level: number;
repositories: number;
totalCommits: number;
recentActivity: boolean;
}
interface GitHubVerificationResult {
success: boolean;
sessionId: string;
profileAttestation: string;
skillAttestations: string[];
repoAttestations: string[];
profileData: GitHubProfileData;
expiresAt: number;
}
Developer Profile Consumer
Implement GitHub credential verification in applications:Copy
class DeveloperProfileVerifier {
private sdk: StellarAttestSDK | SolanaAttestSDK;
constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
this.sdk = sdk;
}
async getDeveloperProfile(userAddress: string): Promise<DeveloperProfile | null> {
try {
// Fetch the main GitHub profile attestation
const attestationData = await this.fetchProfileAttestation(userAddress);
if (!attestationData) return null;
// Fetch supplementary data in parallel
const [skills, repositories] = await Promise.all([
this.getDeveloperSkills(userAddress),
this.getRepositoryContributions(userAddress)
]);
// Build complete profile object
return this.buildCompleteProfile(userAddress, attestationData, skills, repositories);
} catch (error) {
console.error('Error fetching developer profile:', error);
return null;
}
}
Copy
private async fetchProfileAttestation(userAddress: string) {
const profileResult = await this.sdk.fetchAttestation({
schemaUID: 'github-profile-v1',
subject: userAddress
});
// Validate attestation exists and is not revoked
if (profileResult.error || !profileResult.data || profileResult.data.revoked) {
return null;
}
return {
parsed: this.parseAttestationData(profileResult.data.value),
reference: profileResult.data.reference
};
}
Copy
private buildCompleteProfile(
userAddress: string,
attestationData: any,
skills: VerifiedSkill[],
repositories: VerifiedRepository[]
): DeveloperProfile {
const { parsed, reference } = attestationData;
return {
address: userAddress,
github: {
username: parsed.username,
verified: parsed.verified === 'true',
publicRepos: parseInt(parsed.publicRepos),
followers: parseInt(parsed.followers),
totalCommits: parseInt(parsed.totalCommits),
accountAge: parseInt(parsed.accountAge)
},
skills,
repositories,
overallScore: this.calculateDeveloperScore(parsed, skills, repositories),
verifiedAt: parseInt(parsed.timestamp),
attestationUID: reference
};
}
async verifyDeveloperSkill(
userAddress: string,
requiredSkill: string,
minimumLevel: number = 5
): Promise<boolean> {
try {
// This would require a more sophisticated query system
// For now, we'll fetch all skill attestations and filter
const skills = await this.getDeveloperSkills(userAddress);
const skill = skills.find(s => s.language.toLowerCase() === requiredSkill.toLowerCase());
return skill ? skill.level >= minimumLevel : false;
} catch (error) {
console.error('Skill verification failed:', error);
return false;
}
}
async getDeveloperSkills(userAddress: string): Promise<VerifiedSkill[]> {
// In a real implementation, this would query multiple skill attestations
// For now, we'll return a placeholder structure
return [];
}
async getRepositoryContributions(userAddress: string): Promise<VerifiedRepository[]> {
// In a real implementation, this would query repository contribution attestations
return [];
}
private parseAttestationData(value: string): Record<string, string> {
const pairs = value.split(',');
const result: Record<string, string> = {};
pairs.forEach(pair => {
const [key, val] = pair.split(':');
result[key] = val;
});
return result;
}
private calculateDeveloperScore(
profile: any,
skills: VerifiedSkill[],
repositories: VerifiedRepository[]
): number {
let score = 0;
// Profile score (40% weight)
score += Math.min(40, profile.totalCommits / 100); // Up to 40 points for commits
score += Math.min(10, profile.followers / 10); // Up to 10 points for followers
score += Math.min(10, profile.publicRepos / 5); // Up to 10 points for repos
// Skills score (30% weight)
const avgSkillLevel = skills.reduce((sum, skill) => sum + skill.level, 0) / skills.length || 0;
score += (avgSkillLevel / 10) * 30;
// Repository score (30% weight)
const totalStars = repositories.reduce((sum, repo) => sum + repo.stars, 0);
score += Math.min(30, totalStars / 10);
return Math.round(Math.min(100, score));
}
}
Copy
interface DeveloperProfile {
address: string;
github: {
username: string;
verified: boolean;
publicRepos: number;
followers: number;
totalCommits: number;
accountAge: number;
};
skills: VerifiedSkill[];
repositories: VerifiedRepository[];
overallScore: number;
verifiedAt: number;
attestationUID: string;
}
interface VerifiedSkill {
language: string;
level: number;
repositories: number;
recentActivity: boolean;
}
interface VerifiedRepository {
name: string;
commits: number;
stars: number;
language: string;
}
Integration Patterns
Bounty Platform Integration
Use GitHub credentials for bounty eligibility:Copy
class BountyPlatform {
private profileVerifier: DeveloperProfileVerifier;
constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
this.profileVerifier = new DeveloperProfileVerifier(sdk);
}
async checkBountyEligibility(
userAddress: string,
bountyRequirements: BountyRequirements
): Promise<EligibilityResult> {
const profile = await this.profileVerifier.getDeveloperProfile(userAddress);
if (!profile) {
return {
eligible: false,
reason: 'No verified GitHub profile found',
suggestions: ['Complete GitHub verification to participate in bounties']
};
}
const checks = {
minimumCommits: profile.github.totalCommits >= bountyRequirements.minimumCommits,
minimumRepos: profile.github.publicRepos >= bountyRequirements.minimumRepos,
requiredSkills: bountyRequirements.requiredSkills.every(skill =>
this.profileVerifier.verifyDeveloperSkill(userAddress, skill, bountyRequirements.minimumSkillLevel)
),
accountAge: profile.github.accountAge >= bountyRequirements.minimumAccountAge
};
const failedChecks = Object.entries(checks)
.filter(([, passed]) => !passed)
.map(([check]) => check);
return {
eligible: failedChecks.length === 0,
reason: failedChecks.length > 0 ? `Failed requirements: ${failedChecks.join(', ')}` : undefined,
profile,
score: profile.overallScore,
suggestions: this.generateSuggestions(failedChecks, bountyRequirements)
};
}
private generateSuggestions(
failedChecks: string[],
requirements: BountyRequirements
): string[] {
const suggestions = [];
if (failedChecks.includes('minimumCommits')) {
suggestions.push(`Increase your GitHub activity. Need ${requirements.minimumCommits} total commits.`);
}
if (failedChecks.includes('requiredSkills')) {
suggestions.push(`Develop proficiency in: ${requirements.requiredSkills.join(', ')}`);
}
if (failedChecks.includes('accountAge')) {
suggestions.push('GitHub account too new. Continue building your development history.');
}
return suggestions;
}
}
interface BountyRequirements {
minimumCommits: number;
minimumRepos: number;
requiredSkills: string[];
minimumSkillLevel: number;
minimumAccountAge: number; // days
}
interface EligibilityResult {
eligible: boolean;
reason?: string;
profile?: DeveloperProfile;
score?: number;
suggestions: string[];
}
Team Formation System
Enable skill-based team matching:Copy
class DeveloperTeamMatcher {
private profileVerifier: DeveloperProfileVerifier;
constructor(sdk: StellarAttestSDK | SolanaAttestSDK) {
this.profileVerifier = new DeveloperProfileVerifier(sdk);
}
async findTeammates(
userAddress: string,
projectRequirements: ProjectRequirements
): Promise<TeammateRecommendation[]> {
const userProfile = await this.profileVerifier.getDeveloperProfile(userAddress);
if (!userProfile) {
throw new Error('User must have verified GitHub profile');
}
// In a real implementation, this would query a database of developer profiles
const candidates = await this.getCandidateDevelopers(projectRequirements);
return candidates
.map(candidate => this.calculateCompatibility(userProfile, candidate, projectRequirements))
.sort((a, b) => b.compatibilityScore - a.compatibilityScore)
.slice(0, 10); // Top 10 matches
}
private calculateCompatibility(
user: DeveloperProfile,
candidate: DeveloperProfile,
requirements: ProjectRequirements
): TeammateRecommendation {
let score = 0;
const reasons = [];
// Skill complementarity
const userSkills = new Set(user.skills.map(s => s.language));
const candidateSkills = new Set(candidate.skills.map(s => s.language));
const skillOverlap = new Set([...userSkills].filter(x => candidateSkills.has(x)));
const skillComplementarity = new Set([...candidateSkills].filter(x => !userSkills.has(x)));
// Prefer candidates with complementary skills
score += skillComplementarity.size * 10;
if (skillComplementarity.size > 0) {
reasons.push(`Brings additional skills: ${Array.from(skillComplementarity).join(', ')}`);
}
// Experience level matching
const experienceGap = Math.abs(user.overallScore - candidate.overallScore);
if (experienceGap < 20) {
score += 20;
reasons.push('Similar experience level');
}
// Required skills coverage
const requiredSkillsCovered = requirements.requiredSkills.filter(skill =>
candidateSkills.has(skill)
);
score += requiredSkillsCovered.length * 15;
if (requiredSkillsCovered.length > 0) {
reasons.push(`Covers required skills: ${requiredSkillsCovered.join(', ')}`);
}
return {
profile: candidate,
compatibilityScore: Math.min(100, score),
reasons,
complementarySkills: Array.from(skillComplementarity),
sharedSkills: Array.from(skillOverlap)
};
}
private async getCandidateDevelopers(requirements: ProjectRequirements): Promise<DeveloperProfile[]> {
// Placeholder - would query actual developer database
return [];
}
}
interface ProjectRequirements {
requiredSkills: string[];
teamSize: number;
experienceLevel: 'junior' | 'mid' | 'senior' | 'mixed';
duration: number; // days
}
interface TeammateRecommendation {
profile: DeveloperProfile;
compatibilityScore: number;
reasons: string[];
complementarySkills: string[];
sharedSkills: string[];
}
Best Practices
Verification Security
Implement robust account ownership verification:Copy
class SecureGitHubVerification {
static async generateVerificationChallenge(
userAddress: string
): Promise<VerificationChallenge> {
const nonce = crypto.randomBytes(32).toString('hex');
const timestamp = Math.floor(Date.now() / 1000);
const message = `Verify GitHub account for wallet ${userAddress} at ${timestamp} with nonce ${nonce}`;
return {
challengeId: `gh-verify-${timestamp}-${nonce.slice(0, 8)}`,
message,
instructions: [
'Create a public gist with the exact message above',
'Or commit the message to any public repository',
'Submit the gist ID or commit SHA as proof'
],
expiresAt: timestamp + 3600 // 1 hour
};
}
static async verifyChallenge(
challenge: VerificationChallenge,
proof: string,
githubUsername: string
): Promise<boolean> {
// Verify challenge hasn't expired
if (Date.now() / 1000 > challenge.expiresAt) {
return false;
}
// Verify proof contains challenge message
// Implementation would check gist or commit content
return true; // Placeholder
}
}
interface VerificationChallenge {
challengeId: string;
message: string;
instructions: string[];
expiresAt: number;
}
Data Privacy
Protect sensitive GitHub data:Copy
class PrivacyPreservingGitHub {
static async createPrivateSkillAttestation(
userAddress: string,
skillData: SkillAnalysis,
sdk: StellarAttestSDK | SolanaAttestSDK
): Promise<string> {
// Only attest to skill levels without revealing specific repositories
const skillSummary = skillData.skills.map(skill => ({
skill: skill.skill,
level: Math.floor(skill.level / 2) * 2, // Round to even numbers for privacy
category: this.categorizeSkillLevel(skill.level)
}));
const attestation = await sdk.attest({
schemaUID: 'github-skill-private-v1',
subject: userAddress,
value: `skillCount:${skillSummary.length},averageLevel:${Math.round(skillData.overallLevel)},specializations:${skillData.specializations.length},verified:true,timestamp:${Math.floor(Date.now() / 1000)}`,
reference: `private-skills-${Date.now()}`
});
if (attestation.error) {
throw new Error(`Private skill attestation failed: ${attestation.error}`);
}
return attestation.data;
}
private static categorizeSkillLevel(level: number): string {
if (level >= 8) return 'expert';
if (level >= 6) return 'advanced';
if (level >= 4) return 'intermediate';
return 'beginner';
}
}