or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

api

features

charts

charts.mdconditional-formatting.mdvisualizations.md
authorization.mdchangesets.mdcharts-as-code.mdcompiler.mddashboards.mddbt.mdee-features.mdformatting.mdparameters.mdpivot.mdprojects-spaces.mdsql-runner.mdtemplating.mdwarehouse.md
index.md
tile.json

github.mddocs/api/utilities/specialized/

GitHub Integration Utilities

Functions for validating GitHub tokens for integration with GitHub repositories.

Capabilities

This module provides the following functionality:

Core Functions

/**
 * Checks if a value matches GitHub token format
 * @param value - Token string to check
 * @returns true if the value matches a valid GitHub token format
 */
function isGithubToken(value: string): boolean;

/**
 * Validates GitHub token format and returns result with error message
 * @param value - Token string to validate
 * @returns Tuple of [isValid, errorMessage]
 */
function validateGithubToken(value: string): [boolean, string | undefined];

Examples

Basic Token Validation

import { isGithubToken, validateGithubToken } from '@lightdash/common';

// Check if token format is valid
if (isGithubToken('ghp_1234567890abcdef')) {
  console.log('Valid GitHub token format');
}

// Check different token types
console.log(isGithubToken('ghp_abc123')); // true - Personal access token
console.log(isGithubToken('github_pat_xyz')); // true - Fine-grained token
console.log(isGithubToken('ghs_token123')); // true - Server token
console.log(isGithubToken('invalid_token')); // false

// Validate with error message
const [isValid, errorMessage] = validateGithubToken('invalid_token');
if (!isValid) {
  console.error(errorMessage);
  // "GitHub token should start with "github_pat_" or "ghp_""
}

Form Validation

import { validateGithubToken } from '@lightdash/common';

function validateGitHubConnectionForm(formData: {
  repoUrl: string;
  token: string;
}): string | null {
  // Validate token format
  const [isValid, error] = validateGithubToken(formData.token);

  if (!isValid) {
    return error || 'Invalid GitHub token';
  }

  return null; // No errors
}

// Usage
const error = validateGitHubConnectionForm({
  repoUrl: 'https://github.com/user/repo',
  token: 'ghp_mytoken123',
});

if (error) {
  showError(error);
}

API Endpoint Validation

import { validateGithubToken } from '@lightdash/common';

// Validate GitHub token in API request
app.post('/api/integrations/github', async (req, res) => {
  const { repositoryUrl, accessToken } = req.body;

  // Validate token format
  const [isValid, errorMessage] = validateGithubToken(accessToken);

  if (!isValid) {
    return res.status(400).json({
      error: 'Invalid GitHub token',
      details: errorMessage,
    });
  }

  try {
    // Connect to GitHub with validated token
    await connectGitHubRepository(repositoryUrl, accessToken);

    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});

Connection Testing

import { isGithubToken } from '@lightdash/common';

async function testGitHubConnection(token: string, repoUrl: string): Promise<boolean> {
  // First validate token format
  if (!isGithubToken(token)) {
    throw new Error('Invalid GitHub token format. Token should start with "ghp_", "github_pat_", or "ghs_"');
  }

  // Then test actual connection
  try {
    const response = await fetch(repoUrl, {
      headers: {
        Authorization: `token ${token}`,
      },
    });

    return response.ok;
  } catch (error) {
    console.error('GitHub connection failed:', error);
    return false;
  }
}

// Usage
const canConnect = await testGitHubConnection(
  'ghp_mytoken',
  'https://api.github.com/repos/user/repo'
);

DBT GitHub Connection

import { validateGithubToken } from '@lightdash/common';

interface GitHubDbtConnection {
  type: 'github';
  repository: string;
  branch: string;
  personalAccessToken: string;
  projectPath: string;
}

function validateDbtGitHubConnection(
  connection: GitHubDbtConnection
): string[] {
  const errors: string[] = [];

  // Validate required fields
  if (!connection.repository) {
    errors.push('Repository URL is required');
  }

  if (!connection.personalAccessToken) {
    errors.push('Personal access token is required');
  } else {
    // Validate token format
    const [isValid, errorMessage] = validateGithubToken(
      connection.personalAccessToken
    );

    if (!isValid) {
      errors.push(errorMessage || 'Invalid token format');
    }
  }

  if (!connection.branch) {
    errors.push('Branch name is required');
  }

  return errors;
}

// Usage
const connection: GitHubDbtConnection = {
  type: 'github',
  repository: 'https://github.com/myorg/dbt-project',
  branch: 'main',
  personalAccessToken: 'ghp_abc123',
  projectPath: '/dbt',
};

const errors = validateDbtGitHubConnection(connection);
if (errors.length > 0) {
  console.error('Connection validation failed:', errors);
}

Settings Page Validation

import { validateGithubToken } from '@lightdash/common';

function GitHubSettingsForm() {
  const [token, setToken] = useState('');
  const [error, setError] = useState<string | null>(null);

  const handleTokenChange = (newToken: string) => {
    setToken(newToken);

    // Validate on change
    if (newToken) {
      const [isValid, errorMessage] = validateGithubToken(newToken);
      setError(isValid ? null : errorMessage || 'Invalid token');
    } else {
      setError(null);
    }
  };

  const handleSubmit = async () => {
    // Final validation before submit
    const [isValid, errorMessage] = validateGithubToken(token);

    if (!isValid) {
      setError(errorMessage || 'Invalid token');
      return;
    }

    // Save token
    await saveGitHubToken(token);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="password"
        value={token}
        onChange={(e) => handleTokenChange(e.target.value)}
        placeholder="ghp_..."
      />
      {error && <div className="error">{error}</div>}
      <button type="submit" disabled={!!error}>
        Save
      </button>
    </form>
  );
}

Migration Script

import { isGithubToken } from '@lightdash/common';

async function migrateGitHubTokens() {
  const projects = await db.projects.findMany({
    where: {
      dbtConnectionType: 'github',
    },
  });

  for (const project of projects) {
    const token = project.dbtConnection?.personalAccessToken;

    if (token && !isGithubToken(token)) {
      console.warn(
        `Project ${project.id} has invalid GitHub token format. Please update.`
      );
    }
  }
}

Environment Variable Validation

import { validateGithubToken } from '@lightdash/common';

function validateEnvironmentVariables() {
  const githubToken = process.env.GITHUB_TOKEN;

  if (githubToken) {
    const [isValid, error] = validateGithubToken(githubToken);

    if (!isValid) {
      console.error('Invalid GITHUB_TOKEN environment variable:', error);
      process.exit(1);
    }

    console.log('GitHub token validated successfully');
  }
}

// Run on startup
validateEnvironmentVariables();

CLI Tool

import { validateGithubToken } from '@lightdash/common';

async function connectGitHub(options: { token: string; repo: string }) {
  // Validate token format
  const [isValid, errorMessage] = validateGithubToken(options.token);

  if (!isValid) {
    console.error('Error:', errorMessage);
    console.log('GitHub tokens should start with:');
    console.log('  - ghp_ (Personal access tokens)');
    console.log('  - github_pat_ (Fine-grained personal access tokens)');
    console.log('  - ghs_ (Server tokens)');
    process.exit(1);
  }

  console.log('Token format is valid');

  // Continue with connection
  await setupGitHubIntegration(options);
}

Testing

import { isGithubToken, validateGithubToken } from '@lightdash/common';

describe('GitHub token validation', () => {
  describe('isGithubToken', () => {
    it('should accept ghp_ prefix', () => {
      expect(isGithubToken('ghp_1234567890abcdef')).toBe(true);
    });

    it('should accept github_pat_ prefix', () => {
      expect(isGithubToken('github_pat_abc123')).toBe(true);
    });

    it('should accept ghs_ prefix', () => {
      expect(isGithubToken('ghs_token123')).toBe(true);
    });

    it('should reject invalid prefix', () => {
      expect(isGithubToken('invalid_token')).toBe(false);
    });

    it('should reject empty string', () => {
      expect(isGithubToken('')).toBe(false);
    });
  });

  describe('validateGithubToken', () => {
    it('should return true for valid token', () => {
      const [isValid, error] = validateGithubToken('ghp_abc123');
      expect(isValid).toBe(true);
      expect(error).toBeUndefined();
    });

    it('should return error for invalid token', () => {
      const [isValid, error] = validateGithubToken('invalid');
      expect(isValid).toBe(false);
      expect(error).toContain('should start with');
    });
  });
});

Valid Token Prefixes

GitHub uses different token prefixes for different token types:

  • ghp_: Personal access tokens (classic)
  • github_pat_: Fine-grained personal access tokens
  • ghs_: Server-to-server tokens

All of these are considered valid by the validation functions.

Use Cases

  • DBT Cloud IDE Integration: Validate GitHub tokens for DBT project connections
  • Git Sync: Validate tokens for content-as-code Git synchronization
  • API Configuration: Validate tokens in API endpoints for GitHub integrations
  • Form Validation: Real-time validation in settings forms
  • CLI Tools: Validate tokens in command-line tools
  • Environment Setup: Validate tokens on application startup
  • Migration Scripts: Check existing tokens during migrations

Security Notes

  • Format Validation Only: These functions only validate the token format, not whether the token is active or has correct permissions
  • Don't Log Tokens: Never log actual token values in production
  • Secure Storage: Always store tokens securely (encrypted at rest)
  • Token Rotation: Implement token rotation policies
  • Minimum Permissions: Use tokens with minimum required permissions

Related Utilities

  • OAuth Utilities: See oauth.md for OAuth-based GitHub authentication
  • DBT Configuration: Integration with DBT project configuration
  • Environment Variables: Validation of environment-based configuration