一键导入
github-actions
GitHub Actions Best Practices guidance for Fortress Rollback. Use when Writing GitHub Actions workflows, CI debugging, actionlint, caching.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
GitHub Actions Best Practices guidance for Fortress Rollback. Use when Writing GitHub Actions workflows, CI debugging, actionlint, caching.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Crate Publishing guidance for Fortress Rollback. Use when Publishing to crates.io, version bumps, release checklist.
Changelog Practices guidance for Fortress Rollback. Use when Writing CHANGELOG entries, deciding what to document.
Design Decision Log Pattern guidance for Fortress Rollback. Use when Architectural decisions, design alternatives, superseding prior choices.
Repository-wide engineering policy and project context for Fortress Rollback. Use when implementing, diagnosing, reviewing, testing, documenting, or releasing changes in this repository.
Workspace Organization guidance for Fortress Rollback. Use when Organizing workspace, splitting crates, module structure decisions.
Adversarial Handoff Workflow guidance for Fortress Rollback. Use when High-risk reviews, post-incident hardening, escalation from code review.
基于 SOC 职业分类
| name | github-actions |
| description | GitHub Actions Best Practices guidance for Fortress Rollback. Use when Writing GitHub Actions workflows, CI debugging, actionlint, caching. |
actionlint # Lint all workflows
actionlint .github/workflows/ci-security.yml # Lint specific file
actionlint validates: YAML syntax, ${{ }} expressions, step/job references, contexts, and shell scripts via shellcheck.
Assign ${{ }} to variables before using in conditionals (required for glob patterns, recommended for all):
# WRONG: shellcheck sees literal string, warns it can never match
- run: |
if [[ "${{ matrix.test_filter }}" == MULTI:* ]]; then echo "match"; fi
# CORRECT: assign to variable first
- run: |
test_filter="${{ matrix.test_filter }}"
if [[ "$test_filter" == MULTI:* ]]; then echo "match"; fi
Applies to all contexts: matrix.*, inputs.*, env.*, github.*, steps.*.outputs.*, needs.*.result.
| Code | Issue | Fix |
|---|---|---|
| SC2086 | Unquoted variable | Quote: "$VAR" |
| SC2129 | Multiple individual redirects | { echo "a"; echo "b"; } >> file |
| SC2155 | export x=$(cmd) masks exit | x=$(cmd); export x |
| SC2028 | echo with escapes | Use printf |
| SC2035 | Unsafe glob patterns | Prefix with ./ |
| SC2016 | Variables in single quotes | Use double quotes, or suppress if intentional |
# shellcheck disable=SC2016 # Intentional: function body expands at call time
git config --global credential.helper '!f() { echo "password=${GITHUB_TOKEN}"; }; f'
Always add a comment explaining WHY. Be specific -- disable only the specific code.
- name: Set outputs
id: step_id
run: |
{
echo "name=value"
echo "multi_line<<EOF"
echo "line 1"
echo "EOF"
} >> "$GITHUB_OUTPUT"
- name: Set env vars for subsequent steps
run: echo "MY_VAR=value" >> "$GITHUB_ENV"
# RECOMMENDED: Built-in retries
- uses: actions/github-script@v7
with:
retries: 3
retry-exempt-status-codes: 400 401 403 404 422
script: |
await github.rest.issues.createComment({ ... });
Never combine built-in retries with custom withRetry() functions (creates N*M retries).
Use continue-on-error: true only for non-critical steps (comments, labels, status updates).
# Use environment variables, not inline expressions for user input
- run: echo "$PR_TITLE"
env:
PR_TITLE: ${{ github.event.pull_request.title }}
# Use git credential helper instead of embedding tokens in URLs
- run: |
git config --global credential.helper '!f() { echo "password=${GITHUB_TOKEN}"; }; f'
git config --global credential.https://github.com.username "x-access-token"
git clone "https://github.com/owner/repo.wiki.git" _wiki_clone
Clone directories must not conflict with existing repo directories. Use _ prefix:
| Avoid | Use Instead | Why |
|---|---|---|
wiki | _wiki_clone | wiki/ common in repos |
docs | _docs_clone | docs/ exists everywhere |
build | _build_temp | build/ used by many tools |
Or use $RUNNER_TEMP for complete isolation.
permissions:
contents: read # Explicit minimal permissions
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
CARGO_NET_RETRY: 10
Required jobs must not install a floating Rust nightly. Use the repository's canonical dated nightly pin through its local retrying installer. Keep component-sensitive Miri and Godot pins separate and dated. Release preparation and publication likewise use the exact repository-pinned release compiler.
The installer owns bounded retries and emits the selected version; workflows must not duplicate version literals or add ad hoc retry wrappers. Update a pin only in a reviewed PR that exercises every consuming job.
| Job Type | Timeout | Rationale |
|---|---|---|
| Quick checks (fmt, clippy) | 5-10 min | Should be fast |
| Build & Test | 30 min | Standard compile + test |
| Miri (parallelized) | 20 min | ~1000-7000x slower |
| Kani verification | 60-120 min | SMT solving is slow |
| WASM builds | 15 min | Cross-compilation overhead |
| Docker builds | 15-30 min | Slow without cache |
jobs:
build:
timeout-minutes: 30
- uses: Swatinem/rust-cache@v2
with:
shared-key: "ci"
Or manual:
- uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
Split tests across jobs for reasonable times. Use -Zmiri-many-seeds=0..4 for CI:
miri:
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
include:
- { name: "protocol", test_filter: "network::protocol" }
- { name: "sessions", test_filter: "sessions::" }
- { name: "core", test_filter: "MULTI:hash::|rng::|checksum::" }
Handle MULTI: prefix for multiple test groups:
- run: |
test_filter="${{ matrix.test_filter }}"
if [[ "$test_filter" == MULTI:* ]]; then
filters="${test_filter#MULTI:}"
IFS='|' read -ra FILTER_ARRAY <<< "$filters"
for filter in "${FILTER_ARRAY[@]}"; do
cargo miri test --lib -- "$filter"
done
else
cargo miri test --lib -- "$test_filter"
fi
Skip Miri-incompatible tests with #[cfg_attr(miri, ignore)] for tests using real time, sleep, or FFI.
$RUNNER_TEMP (not /tmp) for temp directoriestimeout-minutes: (not timeout command)shell: bash explicitly for consistent behavior# Enable verbose output
env:
ACTIONS_STEP_DEBUG: true
RUST_BACKTRACE: 1
# Debug expressions
- run: echo '${{ toJSON(github) }}'
# Upload logs on failure
- if: failure()
uses: actions/upload-artifact@v4
with:
name: debug-logs
path: test-output.log
actionlint on modified workflow filesrun: blockspermissions: block is minimalruns-on uses valid runner labelsAuto-merge polls gh pr checks --required for the PR head SHA (the primary path). When required-check metadata is unavailable -- no required checks are configured for the branch, or the only required check is the auto-merge job itself -- it falls back to repos/{owner}/{repo}/commits/{sha}/check-runs and …/status. Both paths exclude the auto-merge job's own entries by filtering link/details_url/target_url against GITHUB_RUN_ID.
Failure classification uses an allow-list: only success, skipped, and neutral proceed; everything else (including failure, timed_out, cancelled, action_required, startup_failure, stale, missing/null, or future GitHub-added states) blocks the merge. skipped is allowed because matrix builds and conditional jobs legitimately produce it; neutral is allowed because GitHub-native advisory checks (e.g. dependency-review-action) emit it for non-failure findings.
Three regression guardrails in scripts/tests/test_enable_dependabot_automerge.py lock in this policy:
test_workflow_does_not_set_one_shot_env -- fails CI if the bypass env var is reintroduced.test_workflow_run_command_is_pure_script_invocation -- fails CI if the script is wrapped in timeout, xargs, or any prefix command.test_workflow_timeout_is_sufficient_for_polling -- fails CI if the workflow timeout-minutes falls below 32 minutes (the polling settle ceiling + a 2-minute buffer).Branch protection is a defense layer, not a substitute. Configure main to require the relevant CI checks so GitHub's native auto-merge respects them too -- but the script's own gating remains the source of truth.