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
21 changes: 21 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
cooldown:
default-days: 7
schedule:
interval: "weekly"
day: "monday"
commit-message:
prefix: "ci"
open-pull-requests-limit: 5
groups:
all:
applies-to: version-updates
patterns:
- "*"
update-types:
- "major"
- "minor"
- "patch"
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI

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

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
security-scan:
Comment thread Fixed
name: Security scan
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write # Code Scanning: upload SARIF from OSV (codeql-action/upload-sarif)
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Comment thread Fixed
with:
persist-credentials: false

- name: Run security scan
uses: ./
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
zizmor_persona: pedantic
enable_scorecard: 'false' # scorecard.yml handles this with the required permissions
# osv-scanner scans for dependency vulnerabilities
# python audit is off (not a Python project)
67 changes: 67 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: Release Please

on:
push:
branches: [main]

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

permissions: {}

jobs:
release-please:
name: Release Please
runs-on: ubuntu-latest
environment: release
permissions:
contents: write # Create releases, tags, and release branches
pull-requests: write # Open and update pin README pull requests
steps:
- uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0
id: release
with:
release-type: simple

# Move major version tag (e.g. v1) after a release is cut
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
if: ${{ steps.release.outputs.release_created }}
with:
persist-credentials: false
- name: Tag major version
if: ${{ steps.release.outputs.release_created }}
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
RELEASE_MAJOR: ${{ steps.release.outputs.major }}
RELEASE_TAG_NAME: ${{ steps.release.outputs.tag_name }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git tag -fa "v${RELEASE_MAJOR}" \
-m "Release v${RELEASE_TAG_NAME}"
git push origin "v${RELEASE_MAJOR}" --force

- name: Pin README to release SHA
if: ${{ steps.release.outputs.release_created }}
env:
GH_TOKEN: ${{ github.token }}
RELEASE_SHA: ${{ steps.release.outputs.sha }}
RELEASE_TAG_NAME: ${{ steps.release.outputs.tag_name }}
run: |
sed -i -E \
"s|developmentseed/security-action@[^ ]+( # v[0-9][^ ]*)?|developmentseed/security-action@${RELEASE_SHA} # ${RELEASE_TAG_NAME}|g" \
README.md
git add README.md
git diff --cached --quiet && echo "README unchanged, skipping commit" && exit 0
BRANCH="chore/pin-readme-${RELEASE_TAG_NAME}"
git checkout -b "$BRANCH"
git commit -m "chore: pin README to ${RELEASE_TAG_NAME}"
git push origin "$BRANCH"
gh pr create \
--title "chore: pin README to ${RELEASE_TAG_NAME}" \
--body "Automated: pin README SHA references to release ${RELEASE_TAG_NAME}." \
--base main \
--head "$BRANCH"
36 changes: 36 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Scorecard analysis workflow

on:
push:
branches:
- main
schedule:
# Weekly on Saturdays.
- cron: "30 1 * * 6"

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

permissions:
contents: read
actions: read # Required by Scorecard to evaluate workflow security posture

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
security-events: write # Upload Scorecard SARIF to Code Scanning
id-token: write # GitHub OIDC token for publish_results

steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- uses: ./
with:
enable_scorecard: 'true'
enable_zizmor: 'false'
enable_osv: 'false'
59 changes: 58 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Development Seed composite GitHub Action that gives any repo default security sc
| [zizmor](https://github.com/zizmorcore/zizmor) | ON | GitHub Actions workflow security |
| [osv-scanner](https://github.com/google/osv-scanner) | ON | Dependency vulnerabilities |
| [bandit + pip-audit](https://github.com/developmentseed/action-python-security-auditing) | OFF | Python-specific security (opt-in) |
| [OSSF Scorecard](https://github.com/ossf/scorecard) | OFF | Repository security posture (opt-in, dedicated workflow recommended) |

## Quick start

Expand Down Expand Up @@ -40,6 +41,10 @@ That's it. zizmor and osv-scanner run automatically. Results appear in the repos
| `contents: read` | Required by all scanners to read the repository |
| `security-events: write` | Upload SARIF results to Code Scanning |
| `pull-requests: write` | Only needed when `python_audit_comment_on` is not `never` |
| `actions: read` | Required by Scorecard to evaluate workflow security posture |
| `id-token: write` | Scorecard OIDC token for publishing results to OSSF dashboard |

> The last two permissions are only needed when `enable_scorecard: 'true'`.

## All inputs

Expand All @@ -50,6 +55,7 @@ That's it. zizmor and osv-scanner run automatically. Results appear in the repos
| `enable_zizmor` | `'true'` | Run zizmor workflow linter (opt-out with `'false'`) |
| `enable_osv` | `'true'` | Run osv-scanner (opt-out with `'false'`) |
| `enable_python_audit` | `'false'` | Run bandit + pip-audit (opt-in with `'true'`) |
| `enable_scorecard` | `'false'` | Run OSSF Scorecard (opt-in with `'true'`) |

### zizmor

Expand Down Expand Up @@ -84,6 +90,13 @@ That's it. zizmor and osv-scanner run automatically. Results appear in the repos
| `python_audit_working_directory` | `'.'` | Working directory |
| `python_audit_debug` | `'false'` | Enable debug logging |

### Scorecard

| Input | Default | Description |
|-------|---------|-------------|
| `enable_scorecard` | `'false'` | Run OSSF Scorecard analysis (opt-in with `'true'`) |
| `scorecard_publish_results` | `'true'` | Publish results to OSSF dashboard (default-branch only) |

### Shared

| Input | Default | Description |
Expand Down Expand Up @@ -121,6 +134,50 @@ That's it. zizmor and osv-scanner run automatically. Results appear in the repos
python_audit_pip_audit_block_on: 'all'
```

### OSSF Scorecard

Scorecard requires `id-token: write` and `actions: read` permissions that are broader than what a standard CI job should hold. The recommended pattern is to run it in its **own dedicated workflow** triggered on push to `main` and on a weekly schedule, rather than adding those permissions to your main CI job.

```yaml
# .github/workflows/scorecard.yml
name: Scorecard

on:
push:
branches: [main]
schedule:
- cron: "30 1 * * 6" # weekly on Saturdays

permissions:
contents: read
actions: read # required by Scorecard

jobs:
scorecard:
runs-on: ubuntu-latest
permissions:
security-events: write # upload SARIF to Code Scanning
id-token: write # required by Scorecard
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: developmentseed/security-action@v1
with:
enable_scorecard: 'true'
enable_zizmor: 'false' # already runs in CI
enable_osv: 'false' # already runs in CI
```

Then disable Scorecard in your main CI workflow to avoid the permission requirement there:

```yaml
# .github/workflows/ci.yml
- uses: developmentseed/security-action@v1
with:
enable_scorecard: 'false'
```

### Custom osv-scanner scope

```yaml
Expand All @@ -134,4 +191,4 @@ That's it. zizmor and osv-scanner run automatically. Results appear in the repos

## How it works

The composite action routes your configuration to three independent sub-actions — [zizmor-action](https://github.com/zizmorcore/zizmor-action), [osv-scanner-action](https://github.com/google/osv-scanner-action), and [action-python-security-auditing](https://github.com/developmentseed/action-python-security-auditing) — each running with `continue-on-error: true` so all scanners complete regardless of individual failures. A final aggregation step checks each enabled scanner's outcome and fails the job if any enabled scanner found issues (subject to each scanner's own fail flag).
The composite action routes your configuration to four independent sub-actions — [zizmor-action](https://github.com/zizmorcore/zizmor-action), [osv-scanner-action](https://github.com/google/osv-scanner-action), [action-python-security-auditing](https://github.com/developmentseed/action-python-security-auditing), and optionally [scorecard-action](https://github.com/ossf/scorecard-action) — each running with `continue-on-error: true` so all scanners complete regardless of individual failures. A final aggregation step checks each enabled scanner's outcome and fails the job if any enabled scanner found issues (subject to each scanner's own fail flag).
Loading
Loading