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
38 changes: 31 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,42 @@ name: CI (build & import)
on:
workflow_dispatch:

# Least-privilege token by default
permissions:
contents: read

jobs:
build-smoke:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- uses: actions/setup-python@v6
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
with:
python-version: "3.12"

# Use pipx to avoid un-hashed pip installs in workflows
- name: Install pipx + build tool (pinned)
run: |
set -euxo pipefail
sudo apt-get update
sudo apt-get install -y pipx
pipx ensurepath
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
# build provides the "pyproject-build" console script
pipx install build==1.2.2

- name: Build wheel
run: |
python -m pip install -U pip build setuptools wheel
python -m build
pyproject-build -o dist

- name: Inspect wheel has package files
run: |
Expand All @@ -30,10 +52,12 @@ jobs:
assert len(names) > 0, "Wheel missing decision_security/*"
PY

- name: Install & import smoke
- name: Import smoke from wheel (no install)
run: |
python -m pip install dist/*.whl
python - <<'PY'
import glob, sys
whl = glob.glob("dist/*.whl")[0]
sys.path.insert(0, whl) # allow import from wheel zip
from decision_security.synth import sample
print("Smoke OK:", sample("poisson", 5, lam=1.0))
PY
PY
31 changes: 19 additions & 12 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,42 @@ name: CodeQL

on:
push:
branches: [ "master" ]
branches: [ "main" ]
pull_request:
branches: [ "master" ]
branches: [ "main" ]
schedule:
- cron: "0 3 * * 1" # Mondays 03:00 UTC
workflow_dispatch: {} # to manually trigger the workflow
- cron: "0 3 * * 1"
workflow_dispatch: {}

# Read-only by default
permissions:
contents: read

jobs:
analyze:
name: CodeQL (python)
name: CodeQL (Python)
runs-on: ubuntu-latest

# Only needed to upload SARIF
permissions:
security-events: write # required to upload CodeQL SARIF
contents: read
security-events: write

steps:
- name: Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

# CodeQL doesn't need a build step for Python
- name: Initialize CodeQL
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3
uses: github/codeql-action/init@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
with:
languages: python
queries: +security-extended

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v3
- name: Analyze
uses: github/codeql-action/analyze@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
with:
category: "/language:python"
63 changes: 51 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
name: Publish (PyPI)
name: Release

on:
push:
tags: ["v*"] # e.g., v0.1.0a1, v0.1.0
tags: [ 'v*.*.*' ]
workflow_dispatch: {}

# Read-only by default
permissions:
id-token: write
contents: read

jobs:
build-and-publish:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v6
with: { python-version: "3.12" }
- run: python -m pip install -U pip build
- run: python -m build
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
verbose: true
egress-policy: audit

- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
with:
python-version: "3.12"

- name: Build dists
run: |
pip install -U build
python -m build

- name: Upload build artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dist
path: dist/*

publish-pypi:
if: ${{ false }} # set to true when ready
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # required only for OIDC-based PyPI publish
steps:
- name: Download build artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: dist
path: dist

- name: Publish to PyPI (OIDC)
uses: pypa/gh-action-pypi-publish@f8d218034565c4b29629e190f46f5d54e3637bf4 # v1.12.2
with:
print-hash: true
50 changes: 50 additions & 0 deletions .github/workflows/sast.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: SAST (Semgrep)

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

permissions:
contents: read

jobs:
semgrep:
runs-on: ubuntu-latest
permissions:
security-events: write # needed to upload SARIF

steps:
- name: Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Install pipx + Semgrep (pinned)
run: |
set -euxo pipefail
sudo apt-get update
sudo apt-get install -y pipx
pipx ensurepath
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
pipx install semgrep==1.83.0
semgrep --version

# Note: no --error flag; job will not fail on findings.
- name: Run Semgrep and produce SARIF
run: |
semgrep scan \
--config=p/ci \
--config=p/security-audit \
--metrics=off \
--sarif -o semgrep.sarif

- name: Upload SARIF to Code Scanning
uses: github/codeql-action/upload-sarif@f443b600d91635bebf5b0d9ebc620189c0d6fba5 # v4.30.8
with:
sarif_file: semgrep.sarif
wait-for-processing: true
23 changes: 11 additions & 12 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,39 @@ name: OpenSSF Scorecard

on:
schedule:
- cron: '37 9 * * 2' # Tuesdays 09:37 UTC
- cron: '37 9 * * 2'
push:
branches: [ "master" ]
branches: [ "main" ]
pull_request:
branches: [ "master" ]
branches: [ "main" ]
workflow_dispatch: {}

# Least privilege by default
# Read-only by default
permissions:
contents: read

jobs:
scorecard:
name: Scorecard analysis
runs-on: ubuntu-latest
# Needs OIDC only to publish results to scorecard.dev
permissions:
contents: read
id-token: write # needed only to publish to scorecard.dev
id-token: write
steps:
- name: Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit

# No checkout needed for Scorecard itself
- name: Run Scorecard
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
publish_results: true
results_format: sarif
results_file: results.sarif

# Hand off SARIF to next job (keeps least-privilege here)
- name: Upload SARIF artifact (handoff)
- name: Upload SARIF artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: scorecard-sarif
Expand All @@ -44,18 +43,18 @@ jobs:

upload-sarif:
name: Upload SARIF to Code Scanning
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true
needs: scorecard
runs-on: ubuntu-latest
# Only this job needs to write security events
permissions:
contents: read
security-events: write # confined to this job only
security-events: write
steps:
- name: Checkout (required for fingerprinting)
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

- name: Download SARIF artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v4
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: scorecard-sarif
path: .
Expand Down