Compare commits
1 Commits
bb39f2085b
...
abf9e6471b
| Author | SHA1 | Date | |
|---|---|---|---|
| abf9e6471b |
@ -17,6 +17,8 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build Packages
|
||||
env:
|
||||
VAULT_ROLE_ID: ${{ secrets.RPMBUILDER_VAULT_ROLEID }}
|
||||
run: |
|
||||
make all DISTRO=el/8
|
||||
|
||||
@ -41,6 +43,8 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build Packages
|
||||
env:
|
||||
VAULT_ROLE_ID: ${{ secrets.RPMBUILDER_VAULT_ROLEID }}
|
||||
run: |
|
||||
make all DISTRO=el/9
|
||||
|
||||
|
||||
114
tools/build
114
tools/build
@ -2,7 +2,8 @@
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "requests",
|
||||
# "pyyaml"
|
||||
# "pyyaml",
|
||||
# "hvac"
|
||||
# ]
|
||||
# ///
|
||||
|
||||
@ -20,12 +21,93 @@ import sys
|
||||
import argparse
|
||||
import logging
|
||||
import subprocess
|
||||
import tempfile
|
||||
import shutil
|
||||
import requests
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple, Optional, Dict
|
||||
from typing import List, Tuple
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
import hvac
|
||||
|
||||
|
||||
# ==================== VAULT FUNCTIONS ====================
|
||||
|
||||
def get_vault_client() -> hvac.Client:
|
||||
"""
|
||||
Initialize and authenticate Vault client using AppRole authentication.
|
||||
|
||||
Returns:
|
||||
Authenticated HVAC client
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Get required environment variables
|
||||
vault_addr = os.getenv('VAULT_ADDR', 'https://vault.service.consul:8200')
|
||||
vault_role_id = os.getenv('VAULT_ROLE_ID')
|
||||
|
||||
if not vault_role_id:
|
||||
logger.error("VAULT_ROLE_ID environment variable is required")
|
||||
raise ValueError("VAULT_ROLE_ID environment variable is required")
|
||||
|
||||
# Initialize Vault client
|
||||
client = hvac.Client(url=vault_addr)
|
||||
|
||||
# Authenticate using AppRole
|
||||
try:
|
||||
logger.debug(f"Authenticating to Vault at {vault_addr}")
|
||||
auth_response = client.auth.approle.login(role_id=vault_role_id)
|
||||
|
||||
if not client.is_authenticated():
|
||||
logger.error("Failed to authenticate with Vault")
|
||||
raise Exception("Failed to authenticate with Vault")
|
||||
|
||||
logger.debug("Successfully authenticated with Vault")
|
||||
return client
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Vault authentication failed: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def get_api_tokens() -> Tuple[str, str]:
|
||||
"""
|
||||
Retrieve GitHub and Gitea API tokens from Vault.
|
||||
|
||||
Returns:
|
||||
Tuple of (github_token, gitea_token)
|
||||
|
||||
Raises:
|
||||
Exception if Vault authentication fails or tokens cannot be retrieved
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
client = get_vault_client()
|
||||
|
||||
# Read GitHub token
|
||||
try:
|
||||
github_secret = client.secrets.kv.v2.read_secret_version(
|
||||
path='service/github/neoloc/tokens/read-only-token'
|
||||
)
|
||||
github_token = github_secret['data']['data']['token']
|
||||
logger.debug("Successfully retrieved GitHub token from Vault")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve GitHub token from Vault: {e}")
|
||||
raise Exception(f"Failed to retrieve GitHub token from Vault: {e}")
|
||||
|
||||
# Read Gitea token
|
||||
try:
|
||||
gitea_secret = client.secrets.kv.v2.read_secret_version(
|
||||
path='service/gitea/unkinben/tokens/read-only-packages'
|
||||
)
|
||||
gitea_token = gitea_secret['data']['data']['token']
|
||||
logger.debug("Successfully retrieved Gitea token from Vault")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve Gitea token from Vault: {e}")
|
||||
raise Exception(f"Failed to retrieve Gitea token from Vault: {e}")
|
||||
|
||||
if not github_token or not gitea_token:
|
||||
logger.error("One or both API tokens are empty")
|
||||
raise Exception("One or both API tokens are empty")
|
||||
|
||||
return github_token, gitea_token
|
||||
|
||||
|
||||
# ==================== GITEA API FUNCTIONS ====================
|
||||
@ -79,12 +161,15 @@ def check_package_exists(package_name: str, version: str, release: str) -> bool:
|
||||
|
||||
# Get configuration from environment
|
||||
base_url = os.getenv('GITEA_URL', 'https://git.unkin.net')
|
||||
api_token = os.getenv('GITEA_API_TOKEN')
|
||||
owner = os.getenv('GITEA_OWNER', 'unkin')
|
||||
package_type = os.getenv('GITEA_PACKAGE_TYPE', 'rpm')
|
||||
|
||||
if not api_token:
|
||||
logger.warning("No GITEA_API_TOKEN found. API requests may fail for private repos.")
|
||||
# Get API tokens from Vault - fail hard if unavailable
|
||||
try:
|
||||
_, gitea_token = get_api_tokens()
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve API tokens from Vault: {e}")
|
||||
raise Exception(f"Cannot check package existence without Gitea API token: {e}")
|
||||
|
||||
try:
|
||||
# Normalize version by removing leading zeros (Gitea does this automatically)
|
||||
@ -96,9 +181,7 @@ def check_package_exists(package_name: str, version: str, release: str) -> bool:
|
||||
f"{package_type}/{package_name}/{full_version}"
|
||||
)
|
||||
|
||||
headers = {}
|
||||
if api_token:
|
||||
headers['Authorization'] = f'token {api_token}'
|
||||
headers = {'Authorization': f'token {gitea_token}'}
|
||||
|
||||
logger.debug(f"Checking package existence: {url}")
|
||||
response = requests.get(url, headers=headers, timeout=30)
|
||||
@ -629,15 +712,6 @@ class Builder:
|
||||
try:
|
||||
# Check if package already exists (unless forced)
|
||||
if not force:
|
||||
# Check if we have GITEA_API_TOKEN for reliable package checking
|
||||
api_token = os.getenv('GITEA_API_TOKEN')
|
||||
if not api_token:
|
||||
self.logger.error(
|
||||
f"Skipping {package_info} - GITEA_API_TOKEN missing. "
|
||||
"Cannot verify if package already exists. Use --force to build anyway."
|
||||
)
|
||||
return False
|
||||
|
||||
if check_package_exists(
|
||||
package_info.name,
|
||||
package_info.version,
|
||||
@ -809,4 +883,4 @@ Examples:
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
111
tools/update-gh
111
tools/update-gh
@ -2,7 +2,8 @@
|
||||
# /// script
|
||||
# dependencies = [
|
||||
# "requests",
|
||||
# "pyyaml"
|
||||
# "pyyaml",
|
||||
# "hvac"
|
||||
# ]
|
||||
# ///
|
||||
|
||||
@ -22,8 +23,91 @@ import logging
|
||||
import requests
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, List
|
||||
from typing import Dict, Optional, List, Tuple
|
||||
import re
|
||||
import hvac
|
||||
|
||||
|
||||
# ==================== VAULT FUNCTIONS ====================
|
||||
|
||||
def get_vault_client() -> hvac.Client:
|
||||
"""
|
||||
Initialize and authenticate Vault client using AppRole authentication.
|
||||
|
||||
Returns:
|
||||
Authenticated HVAC client
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Get required environment variables
|
||||
vault_addr = os.getenv('VAULT_ADDR', 'https://vault.service.consul:8200')
|
||||
vault_role_id = os.getenv('VAULT_ROLE_ID')
|
||||
|
||||
if not vault_role_id:
|
||||
logger.error("VAULT_ROLE_ID environment variable is required")
|
||||
raise ValueError("VAULT_ROLE_ID environment variable is required")
|
||||
|
||||
# Initialize Vault client
|
||||
client = hvac.Client(url=vault_addr)
|
||||
|
||||
# Authenticate using AppRole
|
||||
try:
|
||||
logger.debug(f"Authenticating to Vault at {vault_addr}")
|
||||
auth_response = client.auth.approle.login(role_id=vault_role_id)
|
||||
|
||||
if not client.is_authenticated():
|
||||
logger.error("Failed to authenticate with Vault")
|
||||
raise Exception("Failed to authenticate with Vault")
|
||||
|
||||
logger.debug("Successfully authenticated with Vault")
|
||||
return client
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Vault authentication failed: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def get_api_tokens() -> Tuple[str, str]:
|
||||
"""
|
||||
Retrieve GitHub and Gitea API tokens from Vault.
|
||||
|
||||
Returns:
|
||||
Tuple of (github_token, gitea_token)
|
||||
|
||||
Raises:
|
||||
Exception if Vault authentication fails or tokens cannot be retrieved
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
client = get_vault_client()
|
||||
|
||||
# Read GitHub token
|
||||
try:
|
||||
github_secret = client.secrets.kv.v2.read_secret_version(
|
||||
path='service/github/neoloc/tokens/read-only-token'
|
||||
)
|
||||
github_token = github_secret['data']['data']['token']
|
||||
logger.debug("Successfully retrieved GitHub token from Vault")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve GitHub token from Vault: {e}")
|
||||
raise Exception(f"Failed to retrieve GitHub token from Vault: {e}")
|
||||
|
||||
# Read Gitea token
|
||||
try:
|
||||
gitea_secret = client.secrets.kv.v2.read_secret_version(
|
||||
path='service/gitea/unkinben/tokens/read-only-packages'
|
||||
)
|
||||
gitea_token = gitea_secret['data']['data']['token']
|
||||
logger.debug("Successfully retrieved Gitea token from Vault")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to retrieve Gitea token from Vault: {e}")
|
||||
raise Exception(f"Failed to retrieve Gitea token from Vault: {e}")
|
||||
|
||||
if not github_token or not gitea_token:
|
||||
logger.error("One or both API tokens are empty")
|
||||
raise Exception("One or both API tokens are empty")
|
||||
|
||||
return github_token, gitea_token
|
||||
|
||||
|
||||
def setup_logging(verbose=False):
|
||||
@ -65,13 +149,12 @@ def load_env_vars(env_file: Path) -> Dict[str, str]:
|
||||
return env_vars
|
||||
|
||||
|
||||
def get_github_latest_release(repo: str, github_token: str) -> Optional[Dict]:
|
||||
def get_github_latest_release(repo: str) -> Optional[Dict]:
|
||||
"""
|
||||
Get the latest release from GitHub API.
|
||||
|
||||
Args:
|
||||
repo: GitHub repository in format "owner/repo"
|
||||
github_token: GitHub API token
|
||||
|
||||
Returns:
|
||||
Latest release info or None if not found
|
||||
@ -79,6 +162,9 @@ def get_github_latest_release(repo: str, github_token: str) -> Optional[Dict]:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
# Get GitHub token from Vault
|
||||
github_token, _ = get_api_tokens()
|
||||
|
||||
url = f"https://api.github.com/repos/{repo}/releases/latest"
|
||||
headers = {
|
||||
'Authorization': f'token {github_token}',
|
||||
@ -198,13 +284,12 @@ def update_package_metadata(package_dir: Path, new_version: str, dry_run: bool =
|
||||
return False
|
||||
|
||||
|
||||
def check_package_updates(package_dir: Path, github_token: str, dry_run: bool = False) -> bool:
|
||||
def check_package_updates(package_dir: Path, dry_run: bool = False) -> bool:
|
||||
"""
|
||||
Check for updates for a single package.
|
||||
|
||||
Args:
|
||||
package_dir: Path to package directory
|
||||
github_token: GitHub API token
|
||||
dry_run: If True, only show what would be done
|
||||
|
||||
Returns:
|
||||
@ -237,7 +322,7 @@ def check_package_updates(package_dir: Path, github_token: str, dry_run: bool =
|
||||
logger.info(f"Checking {package_name} (current: {current_version}) from {github_repo}")
|
||||
|
||||
# Get latest release from GitHub
|
||||
latest_release = get_github_latest_release(github_repo, github_token)
|
||||
latest_release = get_github_latest_release(github_repo)
|
||||
if not latest_release:
|
||||
return False
|
||||
|
||||
@ -328,14 +413,6 @@ Examples:
|
||||
logger.error(f"RPMs directory not found: {rpms_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
# Load environment variables
|
||||
env_vars = load_env_vars(env_file)
|
||||
github_token = env_vars.get('GITHUB_API_TOKEN')
|
||||
|
||||
if not github_token:
|
||||
logger.error("GITHUB_API_TOKEN not found in env file")
|
||||
sys.exit(1)
|
||||
|
||||
success = True
|
||||
|
||||
if args.package:
|
||||
@ -345,7 +422,7 @@ Examples:
|
||||
logger.error(f"Package directory not found: {package_dir}")
|
||||
sys.exit(1)
|
||||
|
||||
success = check_package_updates(package_dir, github_token, args.dry_run)
|
||||
success = check_package_updates(package_dir, args.dry_run)
|
||||
else:
|
||||
# Check all packages with GitHub repos
|
||||
github_packages = find_packages_with_github(rpms_dir)
|
||||
@ -358,7 +435,7 @@ Examples:
|
||||
|
||||
updated_count = 0
|
||||
for package_dir in github_packages:
|
||||
if check_package_updates(package_dir, github_token, args.dry_run):
|
||||
if check_package_updates(package_dir, args.dry_run):
|
||||
updated_count += 1
|
||||
|
||||
logger.info(f"Successfully processed {updated_count}/{len(github_packages)} packages")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user