mirror of
https://github.com/Anon-Planet/thgtoa.git
synced 2026-05-06 11:34:18 +02:00
5636291c8a
Signed-off-by: nopeitsnothing <no@anonymousplanet.org>
323 lines
9.4 KiB
Python
323 lines
9.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Setup helper for PDF workflow configuration.
|
|
|
|
This script helps you configure the necessary GitHub Secrets for the automated
|
|
PDF build, signing, and VirusTotal scanning workflows.
|
|
|
|
Usage:
|
|
python scripts/setup_workflow.py
|
|
|
|
Requirements:
|
|
- Python 3.8+
|
|
- GPG installed (for key export)
|
|
- Access to GitHub repository settings
|
|
|
|
What it does:
|
|
1. Validates your GPG key setup
|
|
2. Exports the public key for verification
|
|
3. Provides instructions for adding secrets to GitHub
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def repo_root() -> Path:
|
|
return Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def check_gpg_installed() -> bool:
|
|
"""Check if GPG is installed and accessible."""
|
|
try:
|
|
result = subprocess.run(
|
|
["gpg", "--version"],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=10,
|
|
)
|
|
return result.returncode == 0
|
|
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
return False
|
|
|
|
|
|
def list_gpg_keys() -> list[dict]:
|
|
"""List all GPG keys in the keyring."""
|
|
try:
|
|
result = subprocess.run(
|
|
["gpg", "--list-keys", "--with-colons"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
keys = []
|
|
current_key = {}
|
|
|
|
for line in result.stdout.split('\n'):
|
|
if line.startswith('pub:'):
|
|
if current_key:
|
|
keys.append(current_key)
|
|
parts = line.split(':')
|
|
current_key = {
|
|
'type': parts[1],
|
|
'key_id': parts[4],
|
|
'fingerprint': parts[9] if len(parts) > 9 else None,
|
|
'created': parts[5],
|
|
'expires': parts[6],
|
|
'uid': None,
|
|
}
|
|
elif line.startswith('uid:'):
|
|
parts = line.split(':')
|
|
current_key['uid'] = parts[9] if len(parts) > 9 else None
|
|
|
|
if current_key:
|
|
keys.append(current_key)
|
|
|
|
return keys
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error listing GPG keys: {e}")
|
|
return []
|
|
|
|
|
|
def export_public_key(key_id: str, output_file: Path | None = None) -> str | None:
|
|
"""Export a public key in ASCII armor format."""
|
|
try:
|
|
result = subprocess.run(
|
|
["gpg", "--armor", "--export", key_id],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
if output_file:
|
|
output_file.write_text(result.stdout)
|
|
print(f"✓ Public key exported to {output_file}")
|
|
|
|
return result.stdout
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error exporting public key: {e}")
|
|
return None
|
|
|
|
|
|
def export_private_key(key_id: str, output_file: Path | None = None) -> str | None:
|
|
"""Export a private key in ASCII armor format (requires passphrase)."""
|
|
try:
|
|
# This will prompt for passphrase interactively
|
|
result = subprocess.run(
|
|
["gpg", "--armor", "--export-secret-keys", key_id],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
if output_file:
|
|
output_file.write_text(result.stdout)
|
|
print(f"✓ Private key exported to {output_file}")
|
|
|
|
return result.stdout
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Error exporting private key: {e}")
|
|
return None
|
|
|
|
|
|
def validate_gpg_key(key_id: str) -> bool:
|
|
"""Validate that a GPG key has signing capability."""
|
|
try:
|
|
result = subprocess.run(
|
|
["gpg", "--list-keys", "--with-colons", key_id],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
# Check for 's' (signing) in the pub line
|
|
for line in result.stdout.split('\n'):
|
|
if line.startswith('pub:'):
|
|
flags = line.split(':')[1]
|
|
return 's' in flags
|
|
|
|
return False
|
|
|
|
except subprocess.CalledProcessError:
|
|
return False
|
|
|
|
|
|
def print_setup_instructions():
|
|
"""Print instructions for configuring GitHub Secrets."""
|
|
print("\n" + "="*70)
|
|
print("GITHUB SECRETS SETUP INSTRUCTIONS")
|
|
print("="*70)
|
|
|
|
print("""
|
|
To enable the automated PDF workflow, you need to add three secrets to your
|
|
GitHub repository:
|
|
|
|
1. GPG_PRIVATE_KEY
|
|
- Your GPG private key in ASCII armor format
|
|
- Used to sign PDFs and hash files
|
|
- IMPORTANT: Keep this secret! Never commit it publicly
|
|
|
|
2. GPG_PASSPHRASE
|
|
- The passphrase for your GPG private key
|
|
- Required to unlock the private key for signing
|
|
|
|
3. VT_API_KEY (optional but recommended)
|
|
- VirusTotal API key for malware scanning
|
|
- Get a free key at: https://www.virustotal.com/gui/join-us
|
|
|
|
|
|
HOW TO ADD SECRETS:
|
|
|
|
1. Go to your repository on GitHub
|
|
2. Click 'Settings' → 'Secrets and variables' → 'Actions'
|
|
3. Click 'New repository secret' for each secret below:
|
|
|
|
Secret Name | Value Format
|
|
---------------------|--------------------------------------------------
|
|
GPG_PRIVATE_KEY | Paste the entire ASCII armored key (BEGIN PGP...)
|
|
GPG_PASSPHRASE | Your key's passphrase (no special characters issues)
|
|
VT_API_KEY | Your VirusTotal API key
|
|
|
|
|
|
VERIFYING YOUR SETUP:
|
|
|
|
After adding secrets, you can test by:
|
|
1. Going to 'Actions' tab
|
|
2. Selecting 'Build guide PDF' workflow
|
|
3. Clicking 'Run workflow'
|
|
4. Checking if the workflow completes successfully
|
|
|
|
|
|
TROUBLESHOOTING:
|
|
|
|
- If GPG signing fails: Check that your key has signing capability ('s' flag)
|
|
- If passphrase is wrong: Verify you're using the correct passphrase
|
|
- If VT scan fails: Ensure API key is valid and within rate limits
|
|
|
|
|
|
SECURITY NOTES:
|
|
|
|
⚠ NEVER share your private key or passphrase publicly
|
|
⚠ Always use repository secrets, never hardcode in scripts
|
|
⚠ Rotate keys periodically if compromised
|
|
⚠ Use strong passphrases (12+ characters recommended)
|
|
""")
|
|
|
|
|
|
def main() -> int:
|
|
print("\n" + "="*70)
|
|
print("PDF WORKFLOW SETUP HELPER")
|
|
print("="*70)
|
|
|
|
# Check GPG installation
|
|
if not check_gpg_installed():
|
|
print("⚠ WARNING: GPG is not installed or not in PATH")
|
|
print("Please install GPG before continuing:")
|
|
print(" - Linux: sudo apt install gnupg")
|
|
print(" - macOS: brew install gnupg")
|
|
print(" - Windows: https://www.gpg4win.org/")
|
|
print("\nContinuing anyway...")
|
|
|
|
# List available keys
|
|
print("\n🔑 Available GPG Keys:")
|
|
print("-" * 70)
|
|
|
|
keys = list_gpg_keys()
|
|
|
|
if not keys:
|
|
print("No GPG keys found in your keyring.")
|
|
print("Generate a key with: gpg --full-generate-key")
|
|
return 1
|
|
|
|
for i, key in enumerate(keys, 1):
|
|
status = "✓" if validate_gpg_key(key['key_id']) else "✗"
|
|
print(f"\n{i}. {status} Key ID: {key['key_id']}")
|
|
print(f" Fingerprint: {key.get('fingerprint', 'N/A')}")
|
|
print(f" UID: {key.get('uid', 'Unknown')}")
|
|
print(f" Created: {key.get('created', 'Unknown')}")
|
|
|
|
if key.get('expires'):
|
|
print(f" Expires: {key['expires']}")
|
|
|
|
# Ask user to select key
|
|
print("\n" + "-" * 70)
|
|
try:
|
|
choice = input("\nEnter the number of the key you want to use (1-{}): ".format(len(keys)))
|
|
selected_index = int(choice) - 1
|
|
|
|
if not (0 <= selected_index < len(keys)):
|
|
print("Invalid selection!")
|
|
return 1
|
|
|
|
except ValueError:
|
|
print("Invalid input! Please enter a number.")
|
|
return 1
|
|
|
|
selected_key = keys[selected_index]
|
|
|
|
# Validate key has signing capability
|
|
if not validate_gpg_key(selected_key['key_id']):
|
|
print(f"\n⚠ WARNING: Selected key does not have signing capability!")
|
|
print("You need a key with 's' (signing) flag for PDF signatures.")
|
|
confirm = input("Continue anyway? (y/N): ")
|
|
if confirm.lower() != 'y':
|
|
return 1
|
|
|
|
# Export public key
|
|
print(f"\n📤 Exporting public key for {selected_key['uid']}...")
|
|
public_key_file = repo_root() / "pgp" / "workflow-public.asc"
|
|
|
|
public_key = export_public_key(selected_key['key_id'], public_key_file)
|
|
|
|
if not public_key:
|
|
print("Failed to export public key!")
|
|
return 1
|
|
|
|
# Show public key info
|
|
print("\n✓ Public Key Information:")
|
|
print("-" * 70)
|
|
for line in public_key.split('\n')[:5]:
|
|
print(line)
|
|
print("...")
|
|
|
|
# Instructions for private key export
|
|
print("\n🔐 Private Key Export:")
|
|
print("-" * 70)
|
|
print("""
|
|
To get your private key for the GPG_PRIVATE_KEY secret:
|
|
|
|
1. Run this command (you'll be prompted for passphrase):
|
|
gpg --armor --export-secret-keys {} > workflow-private.asc
|
|
|
|
2. Copy the ENTIRE output including BEGIN and END lines
|
|
|
|
3. Add it to GitHub Secrets as 'GPG_PRIVATE_KEY'
|
|
|
|
⚠ IMPORTANT: Keep your private key secure! Never commit it publicly.
|
|
""".format(selected_key['key_id']))
|
|
|
|
# Print setup instructions
|
|
print_setup_instructions()
|
|
|
|
print("\n" + "="*70)
|
|
print("SETUP COMPLETE!")
|
|
print("="*70)
|
|
print(f"\nPublic key saved to: {public_key_file}")
|
|
print("Next steps:")
|
|
print("1. Export your private key (see instructions above)")
|
|
print("2. Add all three secrets to GitHub repository settings")
|
|
print("3. Test the workflow by triggering a manual build")
|
|
print("\nFor more information, see: docs/guide/pdf-workflow.md\n")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|