Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# WHY: the release-PR healer (forkwright/.github release-pr-checks.yml) requires a
# security.yml context on release heads, and this repo had none — every healer tick
# 404'd on a nonexistent workflow and the 0.6.0 release PR could never go green.
# This is typikon's honest security gate, not a stub to satisfy the healer: no Cargo
# manifests exist here (the cargo audit/deny legs of the Rust repos' security.yml
# would scan nothing), so the gate covers what this repo actually ships — the
# uv-locked Python consumer requirements and the tree itself.
name: Security

on:
pull_request:
branches: [main]
push:
branches: [main]
schedule:
# NOTE: daily at 06:41 CST (12:41 UTC). Off-peak minute per the fleet rule
# about avoiding :00/:30 crons; sits clear of harmonia's 05:23 CST scan.
- cron: "41 12 * * *"
workflow_dispatch:

# PROJECT: explicit top-level default deny; job-level permissions grant only what's needed
permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
osv-scanner:
# WHY: scans the one dependency manifest this repo has — the uv-compiled
# Python consumer lock (ci/consumer-python-requirements.lock, requirements
# format with hashes) — against the OSV database on every PR and daily,
# so newly-published CVEs against pinned consumer deps surface even when
# no PR is open.
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@6e4298ebc4db23e847df9b2e2de2939d6f066c67
permissions:
actions: read
contents: read
security-events: write
with:
scan-args: |-
--lockfile=ci/consumer-python-requirements.lock
./

gitleaks:
# WHY: the no-secrets policy must be enforceable from the GitHub side, not
# only by local habit. Scans the working tree, not git history: history is
# not rewritable; new leaks land in the tree.
# WHY binary download, not gitleaks/gitleaks-action: the action requires a
# GITLEAKS_LICENSE key for organization repos; the CLI itself is MIT.
# Checksum-pinned so a compromised release asset cannot pass silently.
name: gitleaks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false # PROJECT: security hardening — never expose token to steps
- name: Install gitleaks
# Pinned to ci/tool-lock.toml (gitleaks entry), not @latest — same
# drift discipline ci/check-tool-lock.py enforces on gate-attestation.yml.
env:
GITLEAKS_VERSION: "8.30.1"
GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
run: |
curl -fsSL --retry 3 \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
-o /tmp/gitleaks.tar.gz
echo "${GITLEAKS_SHA256} /tmp/gitleaks.tar.gz" | sha256sum --check
tar -xzf /tmp/gitleaks.tar.gz -C /tmp gitleaks
/tmp/gitleaks version | grep -qx "${GITLEAKS_VERSION}"
- name: gitleaks scan
run: /tmp/gitleaks dir . --no-banner --redact --exit-code 1
14 changes: 14 additions & 0 deletions ci/tool-lock.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v{version}
placeholder_version = "LYCHEE_VERSION"
placeholder_sha256 = "LYCHEE_SHA256"

[[tool]]
name = "gitleaks"
kind = "archive"
version = "8.30.1"
sha256 = "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
url = "https://github.com/gitleaks/gitleaks/releases/download/v{version}/gitleaks_{version}_linux_x64.tar.gz"
placeholder_version = "GITLEAKS_VERSION"
placeholder_sha256 = "GITLEAKS_SHA256"
# WHY no consumer template consumes these placeholders: gitleaks scans for
# leaked credentials, a repo-hygiene gate with no role in rendering a consumer
# site. The consumer is typikon's own .github/workflows/security.yml, held to
# this entry by the same drift discipline check-tool-lock.py enforces on
# gate-attestation.yml.

# ── npm global installs ────────────────────────────────────────────────────
# NOTE, stated rather than implied: npm has no per-package integrity value a
# global install can be pinned to the way an archive checksum pins a download.
Expand Down
12 changes: 12 additions & 0 deletions release/components.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@
"sha256": "1f4e0ef7f6554a6ed33dd7ac144fb2e1bbed98598e7af973042fc5cd43951c9a"
}
},
{
"name": "gitleaks",
"version": "8.30.1",
"purl": "pkg:github/gitleaks/gitleaks@8.30.1?arch=x86_64&os=linux",
"scope": "required",
"license": "MIT",
"hash": {
"kind": "external-distribution",
"url": "https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz",
"sha256": "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
}
},
{
"name": "zola",
"version": "0.23.3",
Expand Down