Files
gh-epieczko-betty/skills/plugin.publish/SKILL.md
2025-11-29 18:26:08 +08:00

1024 lines
28 KiB
Markdown

---
name: Plugin Publish
description: Publish bundled plugin packages to local, marketplace, or GitHub Releases with dry-run and validation modes
---
# plugin.publish
## Overview
**plugin.publish** is the publication tool that distributes your bundled Betty Framework plugin packages to various targets. It validates package integrity via SHA256 checksums and handles publication to local directories, Claude Marketplace endpoints, or GitHub Releases with automatic creation support. Includes `--dry-run` and `--validate-only` modes for safe testing.
## Purpose
Automates secure plugin distribution by:
- **Validating** SHA256 checksums to ensure package integrity
- **Publishing** to local directories for testing and archival
- **Uploading** to Claude Marketplace API endpoint (simulated, ready for production)
- **Creating** GitHub Releases automatically using gh CLI
- **Tracking** publication metadata for auditing and governance
- **Testing** with dry-run mode before actual publication
- **Validating** packages without publishing using validate-only mode
This ensures consistent, traceable, and secure plugin distribution across all deployment targets.
## What It Does
1. **Validates Package**: Verifies the .tar.gz file exists and is readable
2. **Calculates Checksums**: Computes MD5 and SHA256 hashes for integrity verification
3. **Validates SHA256**: Compares against expected checksum from manifest.json
4. **Loads Metadata**: Extracts plugin info from manifest.json (name, version, author, etc.)
5. **Publishes to Target**:
- **local**: Copies to `dist/published/` with metadata
- **marketplace**: POSTs JSON metadata to Claude Marketplace API (simulated)
- **gh-release**: Creates GitHub Release using gh CLI (with auto-create option)
6. **Supports Modes**:
- **--dry-run**: Shows what would be done without making changes
- **--validate-only**: Only validates checksums without publishing
- **--auto-create**: Automatically creates GitHub Release using gh CLI
7. **Generates Metadata**: Creates publication records for auditing
8. **Reports Results**: Returns publication status with paths and checksums
## Usage
### Basic Usage (Local Target)
```bash
python skills/plugin.publish/plugin_publish.py dist/betty-framework-1.0.0.tar.gz
```
Publishes with defaults:
- Target: `local` (dist/published/)
- Checksum validation: Auto-detected from manifest.json
### Via Betty CLI
```bash
/plugin/publish dist/betty-framework-1.0.0.tar.gz
```
### Publish to Specific Target
```bash
# Publish to local directory
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=local
# Publish to Claude Marketplace (simulated)
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace
# Prepare GitHub Release (files only, manual creation needed)
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release
# Create GitHub Release automatically using gh CLI
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release \
--auto-create
```
### Dry Run and Validation Modes
```bash
# Dry run - show what would happen without making changes
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--dry-run
# Validate only - check checksums without publishing
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--validate-only
# Dry run with GitHub Release
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release \
--auto-create \
--dry-run
```
### With Explicit Checksum Validation
```bash
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=local \
--sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
### With Custom Manifest Path
```bash
python skills/plugin.publish/plugin_publish.py \
/tmp/betty-framework-1.0.0.tar.gz \
--target=release \
--manifest=/tmp/manifest.json
```
### With Custom Marketplace Endpoint
```bash
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--endpoint=https://api.example.com/plugins/upload
```
## Command-Line Arguments
| Argument | Type | Default | Description |
|----------|------|---------|-------------|
| `package_path` | Positional | Required | Path to the .tar.gz package file |
| `--target` | Option | `local` | Publication target: `local`, `marketplace`, or `gh-release` |
| `--sha256` | Option | Auto-detect | Expected SHA256 checksum for validation |
| `--manifest` | Option | Auto-detect | Path to manifest.json |
| `--endpoint` | Option | Claude Marketplace | Marketplace API endpoint URL (for `marketplace` target) |
| `--dry-run` | Flag | False | Show what would be done without making changes |
| `--validate-only` | Flag | False | Only validate checksums without publishing |
| `--auto-create` | Flag | False | Automatically create GitHub Release using gh CLI (for `gh-release` target) |
## Publication Targets
### Local Target
**Purpose**: Copy package to local published directory for testing, archival, or internal distribution.
**Output Location**: `dist/published/`
**Generated Files**:
- `{package-name}.tar.gz` - Copied package file
- `{package-name}.tar.gz.publish.json` - Publication metadata
**Use Cases**:
- Local testing before remote publication
- Internal company archives
- Offline distribution
- Backup copies
**Example**:
```bash
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=local
```
**Output**:
```
dist/published/
├── betty-framework-1.0.0.tar.gz
└── betty-framework-1.0.0.tar.gz.publish.json
```
### Marketplace Target
**Purpose**: Upload plugin metadata to Claude Marketplace API endpoint (currently simulated).
**Output Location**: `dist/published/marketplace/`
**Generated Files**:
- `{package-name}.tar.gz.marketplace-publish.json` - Simulation log with request/response
**Use Cases**:
- Publish to Claude Code Marketplace
- Upload to custom plugin repository
- Submit to enterprise plugin registry
**Current Implementation**: SIMULATED
- Generates complete HTTP POST request with JSON metadata
- Returns mock successful response
- No actual network request made
- Ready for real implementation (add requests library)
**Example**:
```bash
# Standard marketplace publication (simulated)
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace
# With custom endpoint
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--endpoint=https://marketplace.claude.ai/api/v1/plugins
# Dry run first to see what would happen
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--dry-run
```
**JSON Metadata Structure**:
```json
{
"plugin": {
"name": "betty-framework",
"version": "1.0.0",
"description": "...",
"author": { ... },
"license": "MIT",
"homepage": "...",
"repository": "...",
"tags": [...],
"betty_version": ">=0.1.0"
},
"package": {
"filename": "betty-framework-1.0.0.tar.gz",
"size_bytes": 524288,
"checksums": {
"md5": "...",
"sha256": "..."
}
},
"submitted_at": "2025-10-24T12:00:00.000000+00:00"
}
```
### GitHub Release Target
**Purpose**: Create GitHub Releases with auto-generated release notes and automatic upload support.
**Output Location**: `dist/published/releases/`
**Generated Files**:
- `{package-name}.tar.gz` - Copied package file
- `RELEASE_NOTES_v{version}.md` - Auto-generated release notes
- `{package-name}.tar.gz.release.json` - Release metadata
**Use Cases**:
- GitHub Releases publication (manual or automatic)
- Public open-source distribution
- Versioned releases with auto-generated notes
- Official product releases
**Modes**:
1. **Preparation Only** (default): Prepares files for manual release creation
2. **Automatic Creation** (`--auto-create`): Uses gh CLI to create release automatically
**Examples**:
```bash
# Prepare release files only (manual upload needed)
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release
# Automatically create GitHub Release using gh CLI
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release \
--auto-create
# Dry run to see what would be created
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release \
--auto-create \
--dry-run
```
**Requirements for Auto-Create**:
- GitHub CLI (`gh`) must be installed
- Must be authenticated: `gh auth login`
- Must have write access to repository
- Tag must not already exist
**Output**:
```
dist/published/releases/
├── betty-framework-1.0.0.tar.gz
├── RELEASE_NOTES_v1.0.0.md
└── betty-framework-1.0.0.tar.gz.release.json
```
## Operating Modes
### Dry Run Mode (`--dry-run`)
**Purpose**: Test publication without making any changes
**Behavior**:
- Validates package and checksums
- Shows all operations that would be performed
- Does NOT create files, directories, or network requests
- Does NOT create GitHub Releases
- Returns success if all validation passes
**Use Cases**:
- Test before actual publication
- Verify configuration is correct
- Preview what will happen
- CI/CD validation steps
**Example**:
```bash
# Test local publication
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--target=local \
--dry-run
# Test marketplace publication
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--target=marketplace \
--dry-run
# Test GitHub Release creation
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--target=gh-release \
--auto-create \
--dry-run
```
**Output Example**:
```
🔍 DRY RUN MODE - No changes will be made
📦 Publishing to local directory...
Would create directory: /home/user/betty/dist/published
Would copy: /home/user/betty/dist/betty-1.0.0.tar.gz
To: /home/user/betty/dist/published/betty-1.0.0.tar.gz
Would write metadata to: /home/user/betty/dist/published/betty-1.0.0.tar.gz.publish.json
✅ Dry run completed successfully
```
### Validate Only Mode (`--validate-only`)
**Purpose**: Validate package integrity without publishing
**Behavior**:
- Validates package file exists
- Calculates MD5 and SHA256 checksums
- Compares against expected checksums from manifest.json
- Exits immediately after validation
- Does NOT publish to any target
**Use Cases**:
- Verify package integrity before distribution
- CI/CD checksum validation
- Security audits
- Package verification after download
**Example**:
```bash
# Validate package checksums
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--validate-only
```
**Output Example**:
```
🔍 VALIDATE ONLY MODE ENABLED
📦 Package: dist/betty-1.0.0.tar.gz
🎯 Target: local
📄 Manifest: dist/manifest.json
🔍 Validating package checksums...
🔐 Calculating checksums...
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
✅ SHA256 checksum validation: PASSED
================================================================================
✅ VALIDATION SUCCESSFUL
================================================================================
Package is valid and ready for publication.
To publish, run without --validate-only flag:
python skills/plugin.publish/plugin_publish.py dist/betty-1.0.0.tar.gz --target=local
```
**Note**: `--validate-only` takes precedence over `--dry-run` if both are specified.
## Output Files
### Publication Metadata (Local Target)
**File**: `{package-name}.tar.gz.publish.json`
**Structure**:
```json
{
"published_at": "2025-10-24T12:00:00.000000+00:00",
"target": "local",
"package": {
"filename": "betty-framework-1.0.0.tar.gz",
"path": "/home/user/betty/dist/published/betty-framework-1.0.0.tar.gz",
"size_bytes": 524288,
"checksums": {
"md5": "d41d8cd98f00b204e9800998ecf8427e",
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
}
},
"metadata": {
"name": "betty-framework",
"version": "1.0.0",
"description": "Betty Framework is RiskExec's system...",
"author": {
"name": "RiskExec",
"email": "platform@riskexec.com"
},
"license": "MIT"
}
}
```
### Marketplace Publication Simulation Log
**File**: `{package-name}.tar.gz.marketplace-publish.json`
**Structure**:
```json
{
"simulated_at": "2025-10-24T12:00:00.000000+00:00",
"target": "marketplace",
"endpoint": "https://marketplace.claude.ai/api/v1/plugins",
"request": {
"method": "POST",
"url": "https://marketplace.claude.ai/api/v1/plugins",
"headers": {
"Content-Type": "application/json",
"X-Plugin-Name": "betty-framework",
"X-Plugin-Version": "1.0.0",
"X-Package-SHA256": "..."
},
"json": {
"plugin": { ... },
"package": { ... },
"submitted_at": "..."
}
},
"response": {
"status": 200,
"body": {
"success": true,
"message": "Plugin published successfully",
"plugin": {
"id": "betty-framework-1.0.0",
"name": "betty-framework",
"version": "1.0.0",
"published_at": "2025-10-24T12:00:00.000000+00:00",
"download_url": "...",
"listing_url": "https://marketplace.claude.ai/plugins/betty-framework"
},
"checksums": { ... }
}
},
"dry_run": false,
"note": "This is a simulated request. No actual HTTP request was made. To enable real publication, add requests library implementation."
}
```
### GitHub Release Notes
**File**: `RELEASE_NOTES_v{version}.md`
**Auto-generated Content**:
```markdown
# betty-framework v1.0.0
## Release Information
- **Version:** 1.0.0
- **Released:** 2025-10-24
- **Package:** `betty-framework-1.0.0.tar.gz`
## Checksums
Verify the integrity of your download:
```
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
## Installation
1. Download the package: `betty-framework-1.0.0.tar.gz`
2. Verify checksums (see above)
3. Extract: `tar -xzf betty-framework-1.0.0.tar.gz`
4. Install dependencies: `pip install -r requirements.txt`
5. Run: Follow instructions in README.md
## Description
Betty Framework is RiskExec's system for structured, auditable AI-assisted engineering...
## GitHub CLI Commands
To create this release using GitHub CLI:
```bash
# Create release
gh release create v1.0.0 \
--title "betty-framework v1.0.0" \
--notes-file RELEASE_NOTES.md \
betty-framework-1.0.0.tar.gz
```
## Manual Upload
1. Go to: https://github.com/YOUR_ORG/YOUR_REPO/releases/new
2. Tag version: `v1.0.0`
3. Release title: `betty-framework v1.0.0`
4. Upload: `betty-framework-1.0.0.tar.gz`
5. Add checksums to release notes
6. Publish release
```
### Release Metadata
**File**: `{package-name}.tar.gz.release.json`
**Structure**:
```json
{
"prepared_at": "2025-10-24T12:00:00.000000+00:00",
"target": "gh-release",
"version": "1.0.0",
"name": "betty-framework",
"package": {
"filename": "betty-framework-1.0.0.tar.gz",
"path": "/home/user/betty/dist/published/releases/betty-framework-1.0.0.tar.gz",
"size_bytes": 524288,
"checksums": {
"md5": "...",
"sha256": "..."
}
},
"release_notes_path": "/home/user/betty/dist/published/releases/RELEASE_NOTES_v1.0.0.md",
"github_cli_command": "gh release create v1.0.0 --title \"betty-framework v1.0.0\" --notes-file ...",
"metadata": {
"name": "betty-framework",
"version": "1.0.0",
"description": "...",
"author": { ... },
"license": "MIT"
},
"dry_run": false,
"auto_created": true,
"github_release_url": "https://github.com/user/repo/releases/tag/v1.0.0"
}
```
**Note**: The `auto_created` field is `true` if `--auto-create` was used and succeeded, and `github_release_url` will contain the actual release URL.
## Checksum Validation
### Automatic Validation
By default, `plugin.publish` automatically detects and validates checksums from `manifest.json`:
```bash
python skills/plugin.publish/plugin_publish.py dist/betty-framework-1.0.0.tar.gz
```
**Process**:
1. Looks for `dist/manifest.json`
2. Extracts `package.checksums.sha256`
3. Calculates actual SHA256 of package file
4. Compares and validates
### Manual Validation
Explicitly provide expected SHA256:
```bash
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
```
### Validation Output
**Success**:
```
🔍 Validating package checksums...
🔐 Calculating checksums...
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
✅ SHA256 checksum validation: PASSED
```
**Failure**:
```
🔍 Validating package checksums...
🔐 Calculating checksums...
MD5: d41d8cd98f00b204e9800998ecf8427e
SHA256: abc123...
❌ SHA256 checksum validation: FAILED
Expected: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Actual: abc123...
```
## Workflow Integration
### Complete Build and Publish Pipeline
```bash
# Step 1: Build plugin
python skills/plugin.build/plugin_build.py
# Step 2: Validate package integrity
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--validate-only
# Step 3: Dry run to test publication
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=local \
--dry-run
# Step 4: Publish to local for testing
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=local
# Step 5: Publish to Claude Marketplace (simulated)
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace
# Step 6: Create GitHub Release automatically
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=gh-release \
--auto-create
```
### Safe Publication Workflow (Recommended)
```bash
# 1. Validate first
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--validate-only
# 2. Dry run to preview
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--target=marketplace \
--dry-run
# 3. Actual publication
python skills/plugin.publish/plugin_publish.py \
dist/betty-1.0.0.tar.gz \
--target=marketplace
```
### Automated CI/CD Integration
```yaml
# .github/workflows/publish.yml
name: Publish Plugin
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Build plugin
run: python skills/plugin.build/plugin_build.py
- name: Validate package
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--validate-only
- name: Publish to Claude Marketplace
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--target=marketplace
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--target=gh-release \
--auto-create
```
### CI/CD with Dry Run Testing
```yaml
# .github/workflows/test-publish.yml
name: Test Publication
on:
pull_request:
branches: [main]
jobs:
test-publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build plugin
run: python skills/plugin.build/plugin_build.py
- name: Validate package
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--validate-only
- name: Test local publish (dry run)
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--target=local \
--dry-run
- name: Test marketplace publish (dry run)
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--target=marketplace \
--dry-run
- name: Test GitHub Release (dry run)
run: |
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-*.tar.gz \
--target=gh-release \
--auto-create \
--dry-run
```
## Error Handling
### Package Not Found
```
❌ Package file not found: /path/to/missing.tar.gz
```
**Solution**: Verify package path and run `plugin.build` first.
### Invalid Target
```
❌ Invalid target: prod. Must be one of: local, marketplace, gh-release
```
**Solution**: Use one of the valid target values: `local`, `marketplace`, or `gh-release`.
### Checksum Validation Failed
```
❌ SHA256 checksum validation: FAILED
```
**Solution**: Package may be corrupted. Rebuild using `plugin.build`.
### Manifest Not Found
```
⚠️ Manifest not found: /path/to/manifest.json
⚠️ No expected checksum provided - skipping validation
```
**Solution**: Provide `--manifest` path or place manifest.json in package directory.
## Advanced Usage
### Publishing to Multiple Targets
```bash
#!/bin/bash
PACKAGE="dist/betty-framework-1.0.0.tar.gz"
# Validate first
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --validate-only
# Publish to all targets
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=local
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=marketplace
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=gh-release --auto-create
echo "Published to all targets successfully!"
```
### Custom Endpoint Configuration
```bash
# Development marketplace endpoint
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--endpoint=https://dev.marketplace.claude.ai/api/v1/plugins
# Production marketplace endpoint
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--target=marketplace \
--endpoint=https://marketplace.claude.ai/api/v1/plugins
```
### Safe Publication with Validation
```bash
#!/bin/bash
PACKAGE="dist/betty-framework-1.0.0.tar.gz"
# Step 1: Validate checksums
echo "Validating package..."
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --validate-only || exit 1
# Step 2: Dry run for all targets
echo "Running dry runs..."
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=local --dry-run || exit 1
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=marketplace --dry-run || exit 1
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=gh-release --auto-create --dry-run || exit 1
# Step 3: Actual publication
echo "Publishing..."
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=local
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=marketplace
python skills/plugin.publish/plugin_publish.py "$PACKAGE" --target=gh-release --auto-create
echo "All publications completed successfully!"
```
### Verification After Publication
```bash
# Local verification
cd dist/published
sha256sum -c <<< "e3b0c44... betty-framework-1.0.0.tar.gz"
# Extract and inspect
tar -tzf betty-framework-1.0.0.tar.gz | head -20
# Validate manifest
cat betty-framework-1.0.0.tar.gz.publish.json | jq .
```
## Dependencies
- **Python**: 3.11+
- **Standard Library**: os, sys, json, yaml, hashlib, shutil, pathlib, datetime
- **Betty Modules**: betty.config
- **Future**: requests (for actual remote publication)
## Related Skills
- **plugin.build**: Build plugin packages before publishing
- **plugin.sync**: Synchronize plugin.yaml from skill registry
- **registry.update**: Update skill registry entries
- **audit.log**: Log publication events for governance
## Security Considerations
### Checksum Validation
Always validate SHA256 checksums before publication:
- Detects package corruption
- Prevents tampering
- Ensures integrity across distribution channels
### Publication Tracking
All publications are logged with:
- Timestamp (UTC)
- Target destination
- Checksums
- Package metadata
This creates an audit trail for governance and compliance.
### Remote Publication (When Implemented)
For actual remote publication:
- Use HTTPS endpoints only
- Authenticate with API tokens (not in source code)
- Verify TLS certificates
- Implement retry logic with exponential backoff
- Log all API responses
## Troubleshooting
### Issue: Checksum mismatch after build
**Symptom**: SHA256 validation fails immediately after building
**Causes**:
- Manifest.json not generated by plugin.build
- Package file modified after build
- Incorrect manifest path
**Solution**:
```bash
# Rebuild package
python skills/plugin.build/plugin_build.py
# Verify manifest exists
ls -la dist/manifest.json
# Publish with explicit manifest
python skills/plugin.publish/plugin_publish.py \
dist/betty-framework-1.0.0.tar.gz \
--manifest=dist/manifest.json
```
### Issue: Marketplace publication not actually uploading
**Symptom**: No network error but file not on marketplace
**Cause**: Marketplace publication is currently SIMULATED
**Solution**: This is expected behavior. The simulation creates a complete request structure in:
```
dist/published/marketplace/{package}.marketplace-publish.json
```
For actual HTTP upload, add requests library implementation in `publish_marketplace()`.
### Issue: GitHub Release fails
**Symptom**: `gh release create` command fails
**Causes**:
- GitHub CLI not installed
- Not authenticated with GitHub
- Tag already exists
- No write access to repository
**Solutions**:
```bash
# Install GitHub CLI
# macOS: brew install gh
# Linux: sudo apt install gh
# Authenticate
gh auth login
# Check existing releases
gh release list
# Delete existing tag if needed
gh release delete v1.0.0
git push --delete origin v1.0.0
```
## Best Practices
1. **Use validate-only first**: Always run `--validate-only` before publishing to verify package integrity
2. **Dry run before publishing**: Use `--dry-run` to test publication workflows without making changes
3. **Test locally first**: Publish to `--target=local` before marketplace or GitHub Release
4. **Review release notes**: Check auto-generated notes in `dist/published/releases/RELEASE_NOTES_*.md`
5. **Keep publication metadata**: Retain `.json` files for audit trails and compliance
6. **Use version tags consistently**: Follow semantic versioning (e.g., v1.0.0 format)
7. **Automate via CI/CD**: Use GitHub Actions for consistent, reproducible releases
8. **Verify gh CLI setup**: Test `gh auth status` before using `--auto-create`
9. **Backup published packages**: Keep copies for disaster recovery
10. **Use safe publication workflow**: Validate → Dry run → Local → Remote → Release
## Future Enhancements
- [ ] Actual HTTP POST implementation for marketplace target (add requests library)
- [ ] Support for multiple marketplace endpoints (dev, staging, prod)
- [ ] Digital signature support for package verification (GPG signing)
- [ ] Publication rollback mechanism for failed releases
- [ ] Automatic changelog generation from git commits
- [ ] Publication analytics and download tracking
- [ ] Multi-target parallel publication (async)
- [ ] Package verification after publication (download and verify checksums)
- [ ] Support for pre-release and draft GitHub Releases
- [ ] Integration with artifact registries (JFrog, Nexus)
- [ ] Webhook notifications on successful publication
- [ ] Support for package mirroring across multiple registries
---
**Generated by**: Betty Framework
**Version**: 0.1.0
**Last Updated**: 2025-10-24