介绍创建操作的最佳做法

已完成

创建高质量的 GitHub Actions 需要遵循安全、可靠性和可用性的最佳做法。

质量行动的设计原则

单一责任原则

设计专注于做好一件事的行动,而不是企图解决多个问题。

# DON'T: Monolithic action that does everything
name: 'Build-Test-Deploy-Notify Action'
description: 'Builds app, runs tests, deploys to cloud, and sends notifications'

# DO: Focused, composable actions
name: 'Setup Node.js with Cache'
description: 'Sets up Node.js with intelligent dependency caching'

重点行动的优点:

  • 更易于理解、测试和维护
  • 可跨不同工作流方案重复使用
  • 出现问题时进行更简单的调试
  • 在复杂工作流中提高可组合性

可组合和可链接的设计

创建在工作流序列中配合良好的操作:

# Example of well-designed action chain
steps:
  - name: Checkout code
    uses: actions/checkout@v4

  - name: Setup Node.js with cache
    uses: myorg/setup-node-with-cache@v2
    with:
      node-version: "20"

  - name: Run security audit
    uses: myorg/security-audit@v1

  - name: Build and test
    uses: myorg/build-and-test@v3
    with:
      test-command: "npm test"

  - name: Upload coverage
    uses: myorg/upload-coverage@v1
    with:
      coverage-file: "coverage/lcov.info"

操作元数据与文档

完成action.yml的规范编写

name: "Secure Docker Build"
description: "Build and scan Docker images with security best practices"
author: "DevSecOps Team <team@company.com>"

# Visual identity in marketplace
branding:
  icon: "shield"
  color: "blue"

# Clear input definition
inputs:
  dockerfile-path:
    description: "Path to the Dockerfile"
    required: true
    default: "./Dockerfile"
  image-name:
    description: "Name for the built image"
    required: true
  registry-url:
    description: "Container registry URL"
    required: false
    default: "ghcr.io"
  security-scan:
    description: "Enable security vulnerability scanning"
    required: false
    default: "true"
  scan-severity:
    description: "Minimum severity level for scan failures"
    required: false
    default: "HIGH"

# Expected outputs
outputs:
  image-digest:
    description: "SHA256 digest of the built image"
  security-report:
    description: "Path to security scan report"
  image-size:
    description: "Size of the built image in bytes"

runs:
  using: "composite"
  steps:
    - name: Build Docker image
      shell: bash
      run: |
        docker build -f ${{ inputs.dockerfile-path }} -t ${{ inputs.image-name }} .
        echo "image-digest=$(docker inspect --format='{{index .RepoDigests 0}}' ${{ inputs.image-name }})" >> $GITHUB_OUTPUT

    - name: Security scan
      if: inputs.security-scan == 'true'
      shell: bash
      run: |
        # Security scanning logic
        trivy image --severity ${{ inputs.scan-severity }} ${{ inputs.image-name }}

完整的自述文件文档

# Secure Docker Build Action

Build and scan Docker images with integrated security best practices.

## Features

- Flexible Dockerfile path configuration
- Integrated security vulnerability scanning
- Detailed build and security reports
- Optimized for CI/CD pipelines
- Security-first design

## Usage

### Basic usage

```yaml
- name: Build and scan Docker image
  uses: myorg/secure-docker-build@v2
  with:
    dockerfile-path: "./Dockerfile"
    image-name: "my-app:latest"
```

高级配置

- name: Build with custom security settings
  uses: myorg/secure-docker-build@v2
  with:
    dockerfile-path: "./docker/Dockerfile.prod"
    image-name: "my-app:${{ github.sha }}"
    registry-url: "myregistry.azurecr.io"
    security-scan: "true"
    scan-severity: "MEDIUM"

输入

Input Description 必选 违约
dockerfile-path Dockerfile 的路径 是的 ./Dockerfile
image-name Docker 映像名称 是的 -
registry-url 容器注册表 ghcr.io
security-scan 启用安全扫描 true
scan-severity 失败的最低严重性 HIGH

输出

输出 Description
image-digest 生成的映像的 SHA256 摘要
security-report 安全扫描报告的路径
image-size 内置映像的大小(以字节为单位)

安全注意事项

此作实现安全最佳做法:

  • 使用 Trivy 进行漏洞扫描
  • 非根容器运行
  • 最小基础镜像建议
  • 安全报告生成

## Version management and release strategy

### Semantic versioning implementation

```bash
# Release tagging strategy
git tag -a v1.0.0 -m "Initial stable release"
git tag -a v1.0.1 -m "Bug fix: Handle empty Dockerfile paths"
git tag -a v1.1.0 -m "Feature: Add multi-arch build support"
git tag -a v2.0.0 -m "Breaking: Change input parameter names"

# Major version tags for easy consumption
git tag -f v1 v1.1.0  # Point v1 to latest v1.x.x
git tag -f v2 v2.0.0  # Point v2 to latest v2.x.x

发布自动化工作流

name: Release Action

on:
  release:
    types: [published]

jobs:
  tag-major-version:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Update major version tag
        run: |
          TAG=${GITHUB_REF#refs/tags/}
          MAJOR_VERSION=$(echo $TAG | cut -d. -f1)

          git config user.name "Release Bot"
          git config user.email "release@company.com"

          git tag -fa $MAJOR_VERSION -m "Point $MAJOR_VERSION to $TAG"
          git push origin $MAJOR_VERSION --force

动作的安全最佳实践

输入验证和过滤

# In action.yml
inputs:
  file-path:
    description: "Path to file"
    required: true

runs:
  using: "composite"
  steps:
    - name: Validate inputs
      shell: bash
      run: |
        # Validate file path to prevent directory traversal
        FILE_PATH="${{ inputs.file-path }}"

        # Check for dangerous characters
        if [[ "$FILE_PATH" =~ \.\. ]]; then
          echo "Invalid file path: contains '..' (directory traversal)"
          exit 1
        fi

        # Ensure path is within workspace
        REAL_PATH=$(realpath "$FILE_PATH" 2>/dev/null || echo "")
        WORKSPACE_PATH=$(realpath "$GITHUB_WORKSPACE")

        if [[ ! "$REAL_PATH" == "$WORKSPACE_PATH"* ]]; then
          echo "File path outside workspace: $FILE_PATH"
          exit 1
        fi

        echo "File path validated: $FILE_PATH"

安全机密处理

# Proper secret usage in composite actions
- name: Use secrets securely
  shell: bash
  env:
    # Pass secrets through environment variables
    API_TOKEN: ${{ inputs.api-token }}
  run: |
    # Never log secrets
    echo "Authenticating with API..."

    # Use secrets in secure contexts
    curl -H "Authorization: Bearer $API_TOKEN" \
         -H "Content-Type: application/json" \
         https://api.example.com/data

    # Clean up sensitive data
    unset API_TOKEN

最低特权原则

# Define minimal permissions needed
permissions:
  contents: read
  security-events: write # Only if security scanning
  packages: write # Only if publishing packages

jobs:
  secure-action:
    runs-on: ubuntu-latest
    steps:
      - name: Minimal permission usage
        uses: myorg/secure-action@v2
        with:
          # Only pass necessary inputs
          required-input: "value"

性能和效率指南

高效的资源使用

# Optimize action performance
runs:
  using: "composite"
  steps:
    - name: Cache dependencies
      uses: actions/cache@v4
      with:
        path: ~/.cache/my-tool
        key: ${{ runner.os }}-my-tool-${{ hashFiles('**/config.json') }}

    - name: Parallel processing where possible
      shell: bash
      run: |
        # Use background processes for independent tasks
        task1 &
        task2 &
        task3 &

        # Wait for all tasks to complete
        wait

容器操作优化

# Dockerfile for container actions
FROM node:20-alpine

# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001

# Install only production dependencies
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Copy application code
COPY . .

# Set proper ownership
RUN chown -R nextjs:nodejs /app
USER nextjs

ENTRYPOINT ["/entrypoint.sh"]

测试和质量保证

操作测试工作流

name: Test Action

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test-action:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        test-case:
          - name: "Basic functionality"
            dockerfile-path: "./test/Dockerfile.basic"
            expected-outcome: "success"
          - name: "Security scan failure"
            dockerfile-path: "./test/Dockerfile.vulnerable"
            expected-outcome: "failure"
          - name: "Custom configuration"
            dockerfile-path: "./test/Dockerfile.custom"
            security-scan: "false"
            expected-outcome: "success"

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Test action
        id: test
        uses: ./ # Test local action
        with:
          dockerfile-path: ${{ matrix.test-case.dockerfile-path }}
          image-name: "test-image:latest"
          security-scan: ${{ matrix.test-case.security-scan || 'true' }}
        continue-on-error: ${{ matrix.test-case.expected-outcome == 'failure' }}

      - name: Validate outcome
        run: |
          if [[ "${{ steps.test.outcome }}" == "${{ matrix.test-case.expected-outcome }}" ]]; then
            echo "Test passed: ${{ matrix.test-case.name }}"
          else
            echo "Test failed: Expected ${{ matrix.test-case.expected-outcome }}, got ${{ steps.test.outcome }}"
            exit 1
          fi

市场和社区准则

市场提交准备

  • 清除命名:使用描述性、可搜索的名称
  • 质量自述文件:包括使用示例、输入/输出文档
  • 适当的分类:选择适当的市场类别
  • 版本稳定性:确保发布版本稳定并测试

社区参与

# Include community templates
# .github/ISSUE_TEMPLATE/bug_report.yml
name: Bug Report
description: File a bug report for this action
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to report a bug!

  - type: input
    id: action-version
    attributes:
      label: Action Version
      description: Which version of the action are you using?
      placeholder: v2.1.0
    validations:
      required: true

  - type: textarea
    id: workflow-snippet
    attributes:
      label: Workflow Configuration
      description: Share your workflow configuration
      render: yaml
    validations:
      required: true

遵循这些最佳做法可确保 GitHub Actions 对社区具有专业性、安全性、可维护性和价值。 专注于创建既能解决实际问题又易于使用和理解的操作。