Repository navigation
Add a guide for doing assumable identities on Azure (#3328) #520
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: Compile Documentation Bundle (Secure) | |
| on: | |
| push: | |
| branches: [ main ] | |
| paths: | |
| - 'content/**' | |
| - 'scripts/compile_docs.py' | |
| - 'scripts/compile_docs_secure.py' | |
| schedule: | |
| - cron: '0 2 * * 0' # Weekly on Sundays at 2 AM | |
| workflow_dispatch: | |
| inputs: | |
| create_release: | |
| description: 'Create a GitHub release with signed artifacts' | |
| required: false | |
| default: 'false' | |
| permissions: | |
| contents: write # For creating/updating releases | |
| actions: read | |
| id-token: write # For cosign keyless signing | |
| packages: write # For GHCR | |
| # TODO: Split into separate compile (read-only) and publish (write) jobs | |
| jobs: | |
| compile-docs: | |
| if: github.repository == 'chainguard-dev/edu' | |
| runs-on: ubuntu-latest | |
| environment: documentation # Use environment protection rules | |
| steps: | |
| - name: Harden the runner | |
| uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0 | |
| with: | |
| egress-policy: block | |
| allowed-endpoints: > | |
| api.github.com:443 | |
| *.r2.cloudflarestorage.com:443 | |
| apk.cgr.dev:443 | |
| cgr.dev:443 | |
| files.pythonhosted.org:443 | |
| fulcio.sigstore.dev:443 | |
| ghcr.io:443 | |
| github.com:443 | |
| objects.githubusercontent.com:443 | |
| pypi.org:443 | |
| raw.githubusercontent.com:443 | |
| release-assets.githubusercontent.com:443 | |
| rekor.sigstore.dev:443 | |
| timestamp.sigstore.dev:443 | |
| tuf-repo-cdn.sigstore.dev:443 | |
| uploads.github.com:443 | |
| - name: Checkout edu repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| path: edu | |
| persist-credentials: false # Don't persist auth token | |
| - name: Create placeholder directories for compilation | |
| run: | | |
| # Create empty directories for future repos (will be populated when credentials are added) | |
| mkdir -p courses | |
| mkdir -p images-private | |
| echo "# Placeholder" > courses/README.md | |
| echo "# Placeholder" > images-private/README.md | |
| - name: Set up Python | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: '3.10' | |
| - name: Cache Python dependencies | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} | |
| - name: Validate repositories | |
| run: | | |
| # Verify we have the expected repositories | |
| for repo in edu courses images-private; do | |
| if [ ! -d "$repo" ]; then | |
| echo "Error: Expected repository $repo not found" | |
| exit 1 | |
| fi | |
| done | |
| # Check for suspicious files | |
| find . -name "*.sh" -o -name "*.py" | grep -v -E "(compile_docs\.py|create_compressed_docs\.sh)" | while read file; do | |
| echo "Warning: Unexpected script found: $file" | |
| done | |
| - name: Run security scan on Python script | |
| run: | | |
| cd edu | |
| # Install security tools | |
| pip install bandit==1.9.4 safety==3.7.0 | |
| # Scan for security issues | |
| bandit -r scripts/compile_docs.py -f json -o bandit-report.json || true | |
| # Check for critical issues | |
| if [ -f bandit-report.json ]; then | |
| critical_issues=$(python -c "import json; data=json.load(open('bandit-report.json')); print(len([i for i in data.get('results', []) if i.get('issue_severity') == 'HIGH']))") | |
| if [ "$critical_issues" -gt 0 ]; then | |
| echo "Critical security issues found in compile_docs.py" | |
| cat bandit-report.json | |
| exit 1 | |
| fi | |
| fi | |
| - name: Set environment variable for GitHub Actions | |
| run: echo "GITHUB_ACTIONS=true" >> $GITHUB_ENV | |
| - name: Create temporary directory | |
| run: echo "TEMP_BUILD_DIR=$(mktemp -d)" >> $GITHUB_ENV | |
| - name: Compile documentation with resource limits | |
| run: | | |
| cd edu | |
| # Create output directory | |
| mkdir -p $TEMP_BUILD_DIR | |
| # Run with timeout and memory limits, output to temp directory | |
| timeout 600 python3 scripts/compile_docs.py --output $TEMP_BUILD_DIR/chainguard-complete-docs.md | |
| # Verify output file size (max 50MB uncompressed) | |
| if [ -f $TEMP_BUILD_DIR/chainguard-complete-docs.md ]; then | |
| size=$(stat -c%s $TEMP_BUILD_DIR/chainguard-complete-docs.md) | |
| if [ $size -gt 52428800 ]; then | |
| echo "Error: Compiled documentation exceeds 50MB limit" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Generate image catalog | |
| env: | |
| COMMIT_SHA: ${{ github.sha }} | |
| run: | | |
| cd edu | |
| python3 scripts/generate_image_catalog.py \ | |
| --docs "$TEMP_BUILD_DIR/chainguard-complete-docs.md" \ | |
| --mappings data/package-mappings.yaml \ | |
| --output scripts/image-catalog.json \ | |
| --commit "$COMMIT_SHA" | |
| - name: Create compressed versions | |
| run: | | |
| cd $TEMP_BUILD_DIR | |
| # Create compressed versions with integrity checks | |
| gzip -k -9 chainguard-complete-docs.md | |
| zip -9 chainguard-complete-docs.zip chainguard-complete-docs.md | |
| tar -czf chainguard-complete-docs.tar.gz chainguard-complete-docs.md | |
| # Generate checksums | |
| sha256sum chainguard-complete-docs.* > checksums.txt | |
| # Verify compressed files | |
| gzip -t chainguard-complete-docs.md.gz | |
| unzip -t chainguard-complete-docs.zip > /dev/null | |
| tar -tzf chainguard-complete-docs.tar.gz > /dev/null | |
| - name: Install cosign | |
| uses: sigstore/cosign-installer@cad07c2e89fa2edd6e2d7bab4c1aa38e53f76003 # v4.1.1 | |
| - name: Sign documentation with cosign | |
| run: | | |
| cd $TEMP_BUILD_DIR | |
| # Sign the main documentation file (bundle format for cosign v3) | |
| cosign sign-blob chainguard-complete-docs.md \ | |
| --yes \ | |
| --bundle=chainguard-complete-docs.md.bundle | |
| # Sign the checksums file (bundle format for cosign v3) | |
| cosign sign-blob checksums.txt \ | |
| --yes \ | |
| --bundle=checksums.txt.bundle | |
| # Copy verification script | |
| cp $GITHUB_WORKSPACE/edu/scripts/verification.sh . | |
| # Create release bundle with all verification files | |
| tar -czf chainguard-ai-docs.tar.gz \ | |
| chainguard-complete-docs.md \ | |
| chainguard-complete-docs.md.bundle \ | |
| checksums.txt \ | |
| checksums.txt.bundle \ | |
| verification.sh | |
| # Sign the bundle (bundle format for cosign v3) | |
| cosign sign-blob chainguard-ai-docs.tar.gz \ | |
| --yes \ | |
| --bundle=chainguard-ai-docs.tar.gz.bundle | |
| - name: Login to GHCR | |
| if: github.ref == 'refs/heads/main' | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build and push container image | |
| if: github.ref == 'refs/heads/main' | |
| env: | |
| REPO_OWNER: ${{ github.repository_owner }} | |
| COMMIT_SHA: ${{ github.sha }} | |
| run: | | |
| cd edu | |
| # Copy necessary files for container build (rename to match Dockerfile expectations) | |
| cp "$TEMP_BUILD_DIR/chainguard-complete-docs.md" scripts/chainguard-ai-docs.md | |
| cp "$TEMP_BUILD_DIR/checksums.txt" scripts/checksums.txt | |
| # verification.sh is already in scripts/ directory | |
| # Build container with GitHub Container Registry | |
| docker build -f scripts/Dockerfile.ai-docs -t "ghcr.io/$REPO_OWNER/ai-docs:latest" scripts/ | |
| docker tag "ghcr.io/$REPO_OWNER/ai-docs:latest" "ghcr.io/$REPO_OWNER/ai-docs:$COMMIT_SHA" | |
| # Push images and capture digest for signing | |
| DIGEST=$(docker push "ghcr.io/$REPO_OWNER/ai-docs:latest" | grep -oP 'sha256:[a-f0-9]+') | |
| if [ -z "$DIGEST" ]; then | |
| echo "ERROR: Failed to capture image digest from docker push" | |
| exit 1 | |
| fi | |
| docker push "ghcr.io/$REPO_OWNER/ai-docs:$COMMIT_SHA" | |
| # Sign container image by immutable digest | |
| cosign sign --yes "ghcr.io/$REPO_OWNER/ai-docs@$DIGEST" | |
| - name: Scan for sensitive data | |
| run: | | |
| cd edu | |
| # Create a custom gitleaks config to exclude false positives from documentation | |
| cat > .gitleaks.toml << 'EOF' | |
| title = "Gitleaks config for documentation scanning" | |
| [allowlist] | |
| description = "Allowlisted patterns for documentation" | |
| paths = [ | |
| '''.*\.md$''' | |
| ] | |
| regexes = [ | |
| '''`-----BEGIN PRIVATE KEY-----`''', | |
| '''GitHub tokens \(`ghp_`, `ghs_`\)''', | |
| '''id_ed25519\.pub''', | |
| '''\[REDACTED\]''', | |
| '''Example patterns we redact''', | |
| '''-----BEGIN PRIVATE KEY-----''' | |
| ] | |
| EOF | |
| # Install gitleaks (with checksum verification) | |
| wget -q https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz | |
| echo "6e19050a3ee0688265ed3be4c46a0362487d20456ecd547e8c7328eaed3980cb gitleaks_8.18.0_linux_x64.tar.gz" | sha256sum -c - | |
| tar -xzf gitleaks_8.18.0_linux_x64.tar.gz | |
| # Scan compiled documentation for secrets with custom config | |
| ./gitleaks detect --no-git --source $TEMP_BUILD_DIR/ --config .gitleaks.toml --verbose --report-format json --report-path gitleaks-report.json || true | |
| # Check results - parse JSON to see if there are actual findings | |
| if [ -f gitleaks-report.json ]; then | |
| # Check if JSON array is not empty (more than just "[]") | |
| findings_count=$(cat gitleaks-report.json | grep -o '"Description":' | wc -l) | |
| if [ "$findings_count" -gt 0 ]; then | |
| echo "Potential secrets detected in compiled documentation!" | |
| cat gitleaks-report.json | |
| # Double-check if these are real secrets or just documentation examples | |
| if grep -q "Example patterns we redact" gitleaks-report.json; then | |
| echo "Note: These appear to be documentation examples, not actual secrets" | |
| else | |
| exit 1 | |
| fi | |
| else | |
| echo "No secrets detected in compiled documentation" | |
| fi | |
| fi | |