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
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
first-time-pr/** @open-telemetry/shared-workflows-approvers @maryliag
.github/workflows/first-time-pr.yml @open-telemetry/shared-workflows-approvers @maryliag

# OSSF Scorecard
scorecard/** @open-telemetry/shared-workflows-approvers @trask
.github/workflows/scorecard.yml @open-telemetry/shared-workflows-approvers @trask

# Pull request dashboard
pull-request-dashboard/** @open-telemetry/shared-workflows-approvers @trask
.github/scripts/pull-request-dashboard/** @open-telemetry/shared-workflows-approvers @trask
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The YAML files here fall into three categories:

- **Reusable workflows** called by other repos via `uses:` (for example [`zizmor.yml`](./zizmor.yml)). The consumer-facing README lives in a companion docs folder at the repo root (for example [`zizmor/`](../../zizmor/)).
- **Centrally-executed workflows** that run from this repo against opted-in target repositories. Each ships one or more flat YAML files (grouped by filename prefix, e.g. `pull-request-dashboard*.yml`) plus a companion docs folder under root (for example [`pull-request-dashboard/`](../../pull-request-dashboard/)). Supporting scripts and the `repositories.json` opt-in list live under [`../scripts/<workflow-name>/`](../scripts/).
- **Repo-internal workflows** that only run for this repository (for example [`codeql.yml`](./codeql.yml) and [`scorecard.yml`](./scorecard.yml)). These are not shared and have no companion docs folder.
- **Repo-internal workflows** that only run for this repository (for example [`codeql.yml`](./codeql.yml)). These are not shared and have no companion docs folder.

```
<workflow-name>/ # root folder, shared workflows only
Expand Down
62 changes: 51 additions & 11 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
# Reusable workflow — see /scorecard/README.md for consumer documentation.
name: OSSF Scorecard

on:
workflow_call:
push:
branches:
- main
schedule:
- cron: '25 4 * * 4' # weekly at 04:25 (UTC) on Thursday
workflow_dispatch:

permissions: read-all # zizmor: ignore[excessive-permissions] — needed to read repo metadata for Scorecard checks
permissions: {}

concurrency:
# github.workflow here would be the caller's name, not this workflow's.
group: shared-workflow-scorecard-${{ github.ref }}
cancel-in-progress: true

jobs:
# Scorecard restricts what this job may contain while publish_results is true:
# every step must be a `uses:` of an allow-listed action, and no other job may
# request id-token. Filtering therefore happens in the upload job below.
# https://github.com/ossf/scorecard-action#workflow-restrictions
analysis:
name: OSSF Scorecard Analysis
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
security-events: write # Needed for Code scanning upload
id-token: write # Needed for GitHub OIDC token if publish_results is true
contents: read # for actions/checkout
id-token: write # Needed for GitHub OIDC token since publish_results is true
Comment thread
trask marked this conversation as resolved.
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -31,8 +39,7 @@ jobs:
results_format: sarif
publish_results: true

# Upload the results as artifacts (optional). Commenting out will disable
# uploads of run results in SARIF format to the repository Actions tab.
# Also hands the results to the upload job below.
# https://docs.github.com/en/actions/advanced-guides/storing-workflow-data-as-artifacts
- name: "Upload artifact"
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
Expand All @@ -41,9 +48,42 @@ jobs:
path: results.sarif
retention-days: 5

# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
upload:
name: Upload to code scanning
needs: analysis
runs-on: ubuntu-latest
permissions:
contents: read # for actions/checkout, so that upload-sarif can fingerprint results
security-events: write # Needed for Code scanning upload
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: SARIF file

- name: Keep only the checks that report findings
env:
# Deliberately narrow. See the issue for what is left out and why.
# https://github.com/open-telemetry/sig-security/issues/309
INCLUDED_CHECKS: |
BinaryArtifactsID
DangerousWorkflowID
PinnedDependenciesID
TokenPermissionsID
run: |
set -euo pipefail
# The rule definitions stay in place so that code scanning closes the
# alerts already raised for them rather than leaving them stale.
jq --arg included "$INCLUDED_CHECKS" '
($included | split("\n") | map(select(length > 0))) as $keep
| .runs |= map(.results = ((.results // []) | map(select((.ruleId // "") | IN($keep[])))))
' results.sarif > filtered.sarif
echo "kept $(jq '[.runs[] | (.results // [])[]] | length' filtered.sarif) of $(jq '[.runs[] | (.results // [])[]] | length' results.sarif) results"

- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@d1ba80a13dd99fba24a470575428917156a28b43 # v4.37.5
with:
sarif_file: results.sarif
sarif_file: filtered.sarif
11 changes: 6 additions & 5 deletions .github/workflows/zizmor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ on:
- cron: '45 9 * * 5' # weekly at 09:45 (UTC) on Friday
workflow_dispatch:

permissions:
contents: read
permissions: {}

concurrency:
# github.workflow here would be the caller's name, not this workflow's.
group: shared-workflow-zizmor-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
zizmor:
name: Zizmor Security Analysis
runs-on: ubuntu-latest
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
security-events: write # for zizmor to upload SARIF results
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Shared workflows in this repo come in two shapes. Pick the one that fits your us
- **Reusable workflow** — a workflow that other repos call directly via [`uses:`](https://docs.github.com/en/actions/using-workflows/reusing-workflows). The workflow runs in the *calling* repository's context. Example: [`zizmor.yml`](./.github/workflows/zizmor.yml).
- **Centrally-executed workflow** — a workflow that runs *from this repo* against an opted-in list of target repositories. The workflow runs in this repository's context and accesses target repos via the GitHub API. Example: [`pull-request-dashboard/`](./pull-request-dashboard/) plus `pull-request-dashboard*.yml`.

> Workflows that this repo runs only for its own checks (such as [`codeql.yml`](./.github/workflows/codeql.yml) and [`scorecard.yml`](./.github/workflows/scorecard.yml)) are **not** shared. They have no companion docs folder.
> Workflows that this repo runs only for its own checks (such as [`codeql.yml`](./.github/workflows/codeql.yml)) are **not** shared. They have no companion docs folder.

### Layout

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ See [`CONTRIBUTING.md`](./CONTRIBUTING.md) for how to propose a new shared workf
| Name | Description | How to use |
| ---- | ----------- | ---------- |
| [First-time contributor](./first-time-pr/) | Reusable workflow that welcomes first-time contributors on `pull_request_target: opened`: applies a label and posts a customizable welcome comment. | Call via `uses:` from your repo's `pull_request_target` workflow. See the [First-time contributor README](./first-time-pr/README.md) for the snippet. |
| [OSSF Scorecard](./scorecard/) | Reusable workflow that runs [OpenSSF Scorecard](https://github.com/ossf/scorecard), publishes the full result for the badge, and uploads a subset of its checks to code scanning. | Call via `uses:` from your repo's workflow. See the [OSSF Scorecard README](./scorecard/README.md) for the snippet. |
| [Pull Request Dashboard](./pull-request-dashboard/) | Centrally-executed workflow that builds a per-repository pull request triage dashboard (issue body, status, Slack notifications) for opted-in repositories. | Add your repository to [`repositories.json`](./.github/scripts/pull-request-dashboard/repositories.json) and follow the setup in the [workflow's README](./pull-request-dashboard/README.md). |
| [Survey on merged PR](./survey-on-merged-pr/) | Reusable workflow that posts a survey link to a merged PR when the author is a new contributor. | Call via `uses:` from your repo's `pull_request_target: closed` workflow. See the [Survey on merged PR README](./survey-on-merged-pr/README.md) for the snippet. |
| [Workflow failure issue](./workflow-failure-issue/) | Reusable workflow that tracks a workflow's pass/fail state by opening, commenting on, and closing a GitHub issue in the calling repository — useful for scheduled workflows whose failure notifications otherwise reach only a single user. | Call via `uses:` from a final `if: always()` job in the workflow you want to monitor. See the [Workflow failure issue README](./workflow-failure-issue/README.md) for the snippet. |
Expand Down
41 changes: 41 additions & 0 deletions scorecard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# OSSF Scorecard

Reusable GitHub Actions workflow that runs [OpenSSF Scorecard](https://github.com/ossf/scorecard) against the calling repository, publishes the full result to [api.scorecard.dev](https://api.scorecard.dev) (which is what backs the Scorecard badge), and uploads a subset of its checks to the repository's code scanning dashboard.

## How to use

Replace your repository's inline Scorecard workflow (typically `.github/workflows/scorecard.yml`) with:

```yaml
name: OSSF Scorecard

on:
push:
branches: [main]
schedule:
- cron: '25 4 * * 4'
workflow_dispatch:

permissions: {}

jobs:
scorecard:
permissions:
contents: read # for actions/checkout
id-token: write # for Scorecard to publish results
security-events: write # for the SARIF upload to code scanning
uses: open-telemetry/shared-workflows/.github/workflows/scorecard.yml@<sha-or-tag>
```

Pin `<sha-or-tag>` to a commit SHA or release tag in this repository. No inputs or secrets are required.

## What gets filtered

Only these checks are uploaded to code scanning:

- `BinaryArtifactsID`
- `DangerousWorkflowID`
- `PinnedDependenciesID`
- `TokenPermissionsID`

The full result is still published, so the badge and the public `api.scorecard.dev` entry are unaffected.