v0.0.5 #9
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publishing | |
| on: | |
| release: | |
| types: [created] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to publish (e.g., 1.0.0)" | |
| required: true | |
| type: string | |
| prerelease: | |
| description: "Publish as prerelease" | |
| required: false | |
| type: boolean | |
| default: false | |
| target_registries: | |
| description: "Target registries (comma-separated: vscode-marketplace,open-vsx)" | |
| required: false | |
| type: string | |
| default: "vscode-marketplace" | |
| # Security: Minimal permissions following principle of least privilege | |
| permissions: | |
| contents: read | |
| id-token: write # For OIDC token generation (SLSA requirement) | |
| env: | |
| NODE_VERSION: "20" | |
| EXTENSION_DIR: "." | |
| EXTENSION_NAME: "prompt-registry" | |
| jobs: | |
| # Pre-publish security validation | |
| pre-publish-security: | |
| name: Pre-Publish Security Validation | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| security-events: write | |
| id-token: write | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| is_prerelease: ${{ steps.version.outputs.is_prerelease }} | |
| sha256: ${{ steps.package.outputs.sha256 }} | |
| extension_name: ${{ env.EXTENSION_NAME }} | |
| subjects: ${{ steps.package.outputs.subjects }} | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@v2 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| fetch-depth: 0 | |
| - name: Verify release authenticity | |
| if: github.event_name == 'release' | |
| run: | | |
| # Verify the release is properly signed and from authorized user | |
| echo "Verifying release authenticity..." | |
| - name: Determine version and prerelease status | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "release" ]; then | |
| VERSION="${{ github.event.release.tag_name }}" | |
| IS_PRERELEASE="${{ github.event.release.prerelease }}" | |
| else | |
| VERSION="${{ github.event.inputs.version }}" | |
| IS_PRERELEASE="${{ github.event.inputs.prerelease }}" | |
| fi | |
| # Validate version format | |
| if [[ ! "$VERSION" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then | |
| echo "Invalid version format: $VERSION" | |
| exit 1 | |
| fi | |
| # Remove 'v' prefix if present | |
| VERSION=${VERSION#v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: "npm" | |
| cache-dependency-path: "${{ env.EXTENSION_DIR }}/package-lock.json" | |
| - name: Install dependencies with integrity check | |
| working-directory: ${{ env.EXTENSION_DIR }} | |
| run: | | |
| npm ci --fund=false | |
| npm audit --omit=dev --audit-level=moderate | |
| - name: Update version in package.json | |
| working-directory: ${{ env.EXTENSION_DIR }} | |
| run: | | |
| npm version ${{ steps.version.outputs.version }} --no-git-tag-version | |
| - name: Run final security scan | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| scan-type: "fs" | |
| scan-ref: ${{ env.EXTENSION_DIR }} | |
| format: "table" | |
| exit-code: "1" | |
| severity: "CRITICAL,HIGH" | |
| - name: Build and package extension | |
| working-directory: ${{ env.EXTENSION_DIR }} | |
| run: | | |
| npm run compile | |
| npm install -g @vscode/vsce | |
| npm run package:prepare | |
| # Package with integrity verification | |
| if [ "${{ steps.version.outputs.is_prerelease }}" = "true" ]; then | |
| vsce package --pre-release --out ${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix | |
| else | |
| vsce package --out ${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix | |
| fi | |
| npm run package:cleanup | |
| - name: Generate package checksums and attestation | |
| id: package | |
| working-directory: ${{ env.EXTENSION_DIR }} | |
| run: | | |
| # Generate checksums | |
| sha256sum ${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix > checksums.txt | |
| SHA256=$(sha256sum ${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix | cut -d' ' -f1) | |
| echo "sha256=$SHA256" >> $GITHUB_OUTPUT | |
| # Generate base64-encoded subjects for SLSA | |
| FILENAME="${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix" | |
| SUBJECTS=$(echo "$SHA256 $FILENAME" | base64 -w0) | |
| echo "subjects=$SUBJECTS" >> $GITHUB_OUTPUT | |
| # Verify package integrity | |
| echo "Package size: $(stat -c%s ${{env.EXTENSION_NAME}}-${{ steps.version.outputs.version }}.vsix) bytes" | |
| echo "Package SHA256: $SHA256" | |
| - name: Upload package artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: extension-package | |
| path: | | |
| ${{ env.EXTENSION_NAME }}-${{ steps.version.outputs.version }}.vsix | |
| checksums.txt | |
| # Generate SLSA provenance | |
| provenance: | |
| name: Generate SLSA Provenance | |
| needs: pre-publish-security | |
| permissions: | |
| actions: read | |
| id-token: write | |
| contents: write | |
| uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 | |
| with: | |
| base64-subjects: "${{ needs.pre-publish-security.outputs.subjects }}" | |
| upload-assets: true | |
| continue-on-error: true | |
| # Publish to VS Code Marketplace | |
| publish-marketplace: | |
| name: Publish to VS Code Marketplace | |
| runs-on: ubuntu-latest | |
| needs: [pre-publish-security] # provenance] | |
| if: github.event_name == 'release' || contains(github.event.inputs.target_registries, 'vscode-marketplace') | |
| environment: | |
| name: vscode-marketplace | |
| url: https://marketplace.visualstudio.com/items?itemName=AmadeusITGroup.${{ env.EXTENSION_NAME }} | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@v2 | |
| with: | |
| egress-policy: audit | |
| - name: Download package artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: extension-package | |
| - name: Verify package integrity | |
| run: | | |
| # Verify checksums | |
| sha256sum -c checksums.txt | |
| # Additional integrity checks | |
| if [ ! -f "${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix" ]; then | |
| echo "Package file not found!" | |
| exit 1 | |
| fi | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install VSCE | |
| run: npm install -g @vscode/vsce | |
| - name: Publish to VS Code Marketplace | |
| env: | |
| VSCE_PAT: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} | |
| run: | | |
| # Verify token is present | |
| if [ -z "$VSCE_PAT" ]; then | |
| echo "VSCODE_MARKETPLACE_TOKEN secret not configured" | |
| exit 1 | |
| fi | |
| # Publish with explicit version | |
| if [ "${{ needs.pre-publish-security.outputs.is_prerelease }}" = "true" ]; then | |
| vsce publish --pre-release --packagePath ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix | |
| else | |
| vsce publish --packagePath ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix | |
| fi | |
| # Publish to Open VSX Registry | |
| publish-openvsx: | |
| name: Publish to Open VSX Registry | |
| runs-on: ubuntu-latest | |
| needs: [pre-publish-security] # provenance] | |
| # Note: we are not ready to publish it to OpenVSX Registry | |
| if: contains(github.event.inputs.target_registries, 'open-vsx') | |
| environment: | |
| name: open-vsx | |
| url: https://open-vsx.org/extension/AmadeusITGroup/prompt-registry | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@v2 | |
| with: | |
| egress-policy: audit | |
| - name: Download package artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: extension-package | |
| - name: Verify package integrity | |
| run: | | |
| sha256sum -c checksums.txt | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Install OVSX CLI | |
| run: npm install -g ovsx | |
| - name: Publish to Open VSX Registry | |
| env: | |
| OVSX_PAT: ${{ secrets.OPEN_VSX_TOKEN }} | |
| run: | | |
| # Verify token is present | |
| if [ -z "$OVSX_PAT" ]; then | |
| echo "OPEN_VSX_TOKEN secret not configured" | |
| exit 1 | |
| fi | |
| # Publish to Open VSX | |
| ovsx publish ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix -p $OVSX_PAT | |
| # Create installation bundles | |
| create-bundles: | |
| name: Create Installation Bundles | |
| runs-on: ubuntu-latest | |
| needs: [pre-publish-security, publish-marketplace, publish-openvsx] | |
| if: always() && (needs.publish-marketplace.result == 'success' || needs.publish-openvsx.result == 'success') | |
| permissions: | |
| contents: write | |
| id-token: write | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@v2 | |
| with: | |
| egress-policy: audit | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false | |
| - name: Download package artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: extension-package | |
| - name: Download provenance | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: ${{ needs.provenance.outputs.provenance-name }} | |
| - name: Create installation bundle | |
| run: | | |
| mkdir -p installation-bundle | |
| # Copy extension package | |
| cp ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix installation-bundle/ | |
| cp checksums.txt installation-bundle/ | |
| # Copy provenance | |
| cp *.intoto.jsonl installation-bundle/ || true | |
| # Create installation script | |
| cat > installation-bundle/install.sh << 'INSTALL_EOF' | |
| #!/bin/bash | |
| set -e | |
| echo "Installing Prompt Registry VSCode Extension v${{ needs.pre-publish-security.outputs.version }}" | |
| # Verify checksums | |
| if command -v sha256sum &> /dev/null; then | |
| echo "Verifying package integrity..." | |
| sha256sum -c checksums.txt | |
| fi | |
| # Install extension | |
| if command -v code &> /dev/null; then | |
| echo "Installing extension using VS Code CLI..." | |
| code --install-extension ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix | |
| echo "Installation complete!" | |
| else | |
| echo "VS Code CLI not found. Please install the extension manually:" | |
| echo "1. Open VS Code" | |
| echo "2. Press Ctrl+Shift+P (Cmd+Shift+P on Mac)" | |
| echo "3. Type 'Extensions: Install from VSIX'" | |
| echo "4. Select the ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix file" | |
| fi | |
| INSTALL_EOF | |
| # Create Windows installation script | |
| cat > installation-bundle/install.bat << 'INSTALL_BAT_EOF' | |
| @echo off | |
| echo Installing Prompt Registry VSCode Extension v${{ needs.pre-publish-security.outputs.version }} | |
| where code >nul 2>nul | |
| if %ERRORLEVEL% == 0 ( | |
| echo Installing extension using VS Code CLI... | |
| code --install-extension ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix | |
| echo Installation complete! | |
| ) else ( | |
| echo VS Code CLI not found. Please install the extension manually: | |
| echo 1. Open VS Code | |
| echo 2. Press Ctrl+Shift+P | |
| echo 3. Type "Extensions: Install from VSIX" | |
| echo 4. Select the ${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix file | |
| ) | |
| pause | |
| INSTALL_BAT_EOF | |
| # Make scripts executable | |
| chmod +x installation-bundle/install.sh | |
| # Create README | |
| cat > installation-bundle/README.md << 'README_EOF' | |
| # Prompt Registry VSCode Extension Installation Bundle | |
| ## Version: ${{ needs.pre-publish-security.outputs.version }} | |
| This bundle contains the Prompt Registry VSCode Extension package and installation scripts. | |
| ### Security Information | |
| - **Package Integrity**: Verified with SHA256 checksums | |
| - **SLSA Provenance**: Included for supply chain verification | |
| - **Signed Release**: This package was built and signed using secure CI/CD practices | |
| ### Installation Options | |
| #### Option 1: Automatic Installation (Recommended) | |
| **Linux/macOS:** | |
| ```bash | |
| chmod +x install.sh | |
| ./install.sh | |
| ``` | |
| **Windows:** | |
| ```cmd | |
| install.bat | |
| ``` | |
| #### Option 2: Manual Installation | |
| 1. Open VS Code | |
| 2. Press `Ctrl+Shift+P` (`Cmd+Shift+P` on Mac) | |
| 3. Type "Extensions: Install from VSIX" | |
| 4. Select the `${{env.EXTENSION_NAME}}-${{ needs.pre-publish-security.outputs.version }}.vsix` file | |
| ### Verification | |
| To verify the package integrity: | |
| ```bash | |
| sha256sum -c checksums.txt | |
| ``` | |
| ### Support | |
| For issues and support, please visit: | |
| https://github.com/AmadeusITGroup/prompt-registry/issues | |
| README_EOF | |
| # Create bundle archive | |
| zip -r ${{env.EXTENSION_NAME}}-vscode-extension-${{ needs.pre-publish-security.outputs.version }}-bundle.zip installation-bundle/ | |
| - name: Upload bundle to release | |
| if: github.event_name == 'release' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| files: | | |
| ${{env.EXTENSION_NAME}}-vscode-extension-${{ needs.pre-publish-security.outputs.version }}-bundle.zip | |
| tag_name: ${{ github.event.release.tag_name }} | |
| - name: Upload bundle artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: installation-bundle | |
| path: ${{env.EXTENSION_NAME}}-vscode-extension-${{ needs.pre-publish-security.outputs.version }}-bundle.zip | |
| # Security notification | |
| security-notification: | |
| name: Security Notification | |
| runs-on: ubuntu-latest | |
| needs: | |
| [ | |
| pre-publish-security, | |
| publish-marketplace, | |
| publish-openvsx, | |
| create-bundles, | |
| ] | |
| if: always() | |
| steps: | |
| - name: Generate security summary | |
| run: | | |
| echo "## 🔒 Prompt Registry VSCode Extension - Secure Publish Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Version Published: ${{ needs.pre-publish-security.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "### Prerelease: ${{ needs.pre-publish-security.outputs.is_prerelease }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Security Compliance ✅" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ SLSA Level 3 provenance generated" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Package integrity verified with SHA256" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Vulnerability scanning completed" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ Supply chain security validated" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Publication Status" >> $GITHUB_STEP_SUMMARY | |
| echo "- VS Code Marketplace: ${{ needs.publish-marketplace.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- Open VSX Registry: ${{ needs.publish-openvsx.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- Installation Bundle: ${{ needs.create-bundles.result }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Package SHA256: ${{ needs.pre-publish-security.outputs.sha256 }}" >> $GITHUB_STEP_SUMMARY |