Skip to content

feat: add .env.example; add typed contract errors to licensing and me… #85

feat: add .env.example; add typed contract errors to licensing and me…

feat: add .env.example; add typed contract errors to licensing and me… #85

Workflow file for this run

# security.yml — dependency and code security gates.
#
# Closes #883.
#
# The checklists in docs/SECURITY_AUDIT_CHECKLIST.md and
# docs/SECURITY_REVIEW_CHECKLIST.md were prose nobody had to satisfy. This
# workflow is the enforcement point: a PR cannot merge with a known-vulnerable
# dependency, a licence we cannot ship, or a pattern the custom lint rejects.
#
# cargo-audit RustSec advisory database — RUSTSEC-* on anything reachable
# cargo-deny licences, sources, duplicate and banned crates
# security-lint scripts/security_lint.sh — the repo-specific rules
# clippy with the correctness/security lint groups promoted to errors
#
# POLICY LIVES IN ITS OWN FILES, DELIBERATELY
# The policy decision — which advisories are ignorable, which licences are
# acceptable — lives in `deny.toml` (repository root) and `.cargo/audit.toml`,
# each landed as its own reviewable diff (#879, #880) rather than buried in
# this CI file. Both tools read those files automatically, so this workflow
# runs the reviewed policy, not tool defaults.
#
# Every ignored advisory in both files carries the advisory ID and a reason,
# and `unused-ignored-advisory = "warn"` in deny.toml checks that a waiver
# cannot silently rot. The initial-audit baseline and the reasoning for every
# waiver are recorded in docs/STORAGE.md §9.2 and summarised in the PR that
# added them.
#
# `--all-features` and the explicit `deny` assertion below are unchanged on
# purpose: the policy narrows *which* findings are accepted, not *whether* a
# finding is enforced.
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
# Weekly, so a new advisory that affects an already-merged dependency is
# still surfaced on a repo with no activity.
schedule:
- cron: "37 5 * * 1"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: security-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
cargo-audit:
name: cargo audit (RustSec)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the pinned toolchain
run: rustup show
- name: Install cargo-audit
# Install the tool only; the audit itself is run in the next step so
# the outcome is explicit and --deny is applied unconditionally.
uses: taiki-e/install-action@v2
with:
tool: cargo-audit
- name: Audit the dependency graph
# `cargo audit` reads `.cargo/audit.toml` automatically; its
# `[advisories] ignore` list mirrors deny.toml and carries the reason
# for every waiver. Any advisory not in that reviewed list still fails
# the job, so this remains a gate rather than a report.
run: cargo audit --deny warnings
cargo-deny:
name: cargo deny (licences, sources, duplicates)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install the pinned toolchain
run: rustup show
- name: Install cargo-deny
# Install the tool only; the check is run explicitly below so
# --all-features and the deny assertion are applied unconditionally.
uses: taiki-e/install-action@v2
with:
tool: cargo-deny
- name: cargo deny check
# --all-features so a vulnerability hidden behind a feature flag is
# still counted. The `deny` advisory is re-asserted explicitly because
# the default action behaviour is to warn.
run: cargo deny check advisories bans licenses sources all-features
# The repo-specific rules. This is the part that encodes the checklists
# themselves, and the only job here that needs no third-party tool.
security-lint:
name: security lint (checklist rules)
runs-on: ubuntu-latest
steps:
# Full history, not a shallow clone: the lint's key-material rule reports
# a path, not a blob, but a shallow clone would make the tracked-file set
# unrepresentative.
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run the checklist lint
# `--report` first so the full list of findings is in the log even when
# the enforcing run below stops at the first CRITICAL/HIGH.
run: |
./scripts/security_lint.sh --report
./scripts/security_lint.sh
- name: Summarise
if: always()
run: |
{
echo "### security_lint"
echo
echo 'See the job log for the full finding list. Rule ids map to'
echo 'SA-*/T-*/KL-* entries in docs/SECURITY_REVIEW_CHECKLIST.md.'
} >> "$GITHUB_STEP_SUMMARY"
# Clippy restricted to the lint groups that actually describe security
# properties. The full `clippy -- -D warnings` gate lives in ci.yml; this
# job exists so the security surface has its own required check that cannot
# be merged around by a ci.yml change.
clippy-security:
name: clippy (security lints)
runs-on: ubuntu-latest
# Non-blocking while `main` does not compile; see the ci.yml BASELINE block,
# which enumerates the same pre-existing defects.
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Install the pinned toolchain
run: rustup show
- name: Cache cargo registry and host build
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: sec-clippy-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }}-${{ hashFiles('Cargo.lock') }}
restore-keys: |
sec-clippy-${{ runner.os }}-${{ hashFiles('rust-toolchain.toml') }}-
- name: Run the security lint groups as errors
# correctness — unsound code paths (the group that matters here)
# suspicious — bad casts, shadowed bindings, confusing control flow
#
# `pedantic` is deliberately NOT enabled. On a 29-crate Soroban
# workspace it emits thousands of stylistic findings (missing
# `# Errors` sections, `must_use` candidates, long functions) that
# reviewers learn to skip, and a wall of noise is how a security
# signal gets lost. correctness + suspicious is the set with real
# security content.
run: |
cargo clippy --workspace --all-targets \
-- -D clippy::correctness \
-D clippy::suspicious