Prerequisites
- Use the predefined Trusted Build System GitHub.com (see configuration)
- add it to the Organization
- link it to each SignPath Project for GitHub
- Required for audit log evaluation: Install the SignPath GitHub App and allow access to the code repositories.
GitHub Enterprise Server
SignPath hosts an instance of the GitHub connector which is linked to GitHub.com For integrating self-hosted GitHub Enterprise Server instances, contact our support team.
Checks performed by SignPath
The GitHub connector performs the following checks:
- A build was actually performed by a GitHub workflow, not by some other entity in possession of the API token
- Origin metadata is provided by GitHub, not the build script, and can therefore not be forged
- The artifact is stored as a GitHub workflow artifact before it is submitted for signing
- For OSS projects: All jobs of the GitHub worfklow leading up to the signing request were executed on GitHub-hosted agents
Usage
We provide a submit-signing-request action that can be integrated into a GitHub Actions workflow:
steps:
# required for the artifact to be available on the GitHub server
- name: upload unsigned artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v7
with:
path: path/to/your/artifact
- name: submit signing request
uses: signpath/github-action-submit-signing-request@v3
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '<SignPath organization id>'
project-slug: '<SignPath project slug>'
signing-policy-slug: '<SignPath signing policy slug>'
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '/path/to/signed/artifact/directory'
parameters: |
version: ${{ toJSON(some.userinput) }}
myparam: "another param"
ZIP archives
By default, the
upload-artifactaction creates a ZIP archive, which requires the root element of your Artifact Configurations to be of type<zip-file>. If you want to specify your artifact type directly, specifyarchive: falsein theupload-artifactaction. See Usage.Note that there is an open bug in GitHub’s
upload-artifactaction where thenameparameter is ignored and the action fails if another artifact with the same filename has already been uploaded. See issues #769 and #785.
Workflow permissions
If all of the following conditions apply, the required permissions have to be enabled in the workflow definition:
- the GitHub repository is private
- the workflow permissions are set to the default “Read repository contents and packages permissions”
- The SignPath GitHub App is not installed
You can use the following snippet:
permissions: actions: read contents: read
Action input parameters
| Parameter | Default Value | Description |
|---|---|---|
connector-url |
https://githubactions.connectors.signpath.io |
The URL of the SignPath connector. Required if self-hosted. |
api-token |
(mandatory) | The Api Token for a user with submitter permissions in the specified project/signing policy. |
organization-id |
(mandatory) | The SignPath organization ID. |
project-slug |
(mandatory) | The SignPath project slug. |
signing-policy-slug |
(mandatory) | The SignPath signing policy slug. |
artifact-configuration-slug |
default artifact configuration | The SignPath artifact configuration slug. |
github-artifact-id |
(mandatory) | ID of the Github Actions artifact. Must be uploaded using the actions/upload-artifact v4+ action before it can be signed. Use ${{ steps.<step-id>.outputs.artifact-id }} from the preceding actions/upload-artifact action step. |
wait-for-completion |
true |
Wait for the signing request to complete. |
output-artifact-directory |
Path to where the signed artifact will be extracted. If not specified, the task will not download the signed artifact from SignPath. | |
github-token |
secrets.GITHUB_TOKEN |
GitHub access token for reading job details and downloading the artifact. Requires the action:read and content:read permissions. |
wait-for-completion-timeout-in-seconds |
600 |
Maximum time in seconds that the action will wait for the signing request to complete. |
service-unavailable-timeout-in-seconds |
600 |
Total time in seconds that the action will wait for a single service call to succeed (across several retries). |
download-signed-artifact-timeout-in-seconds |
300 |
HTTP timeout when downloading the signed artifact. |
parameters |
Multiline-string of values that map to user-defined parameters in the Artifact Configuration. Use one line per parameter with the format <name>: "<value>" where <value> needs to be a valid JSON string. |
|
skip-decompress |
false |
Set to true if the archive parameter in the upload-artifact action is set to false (i.e. the artifact is not stored as a ZIP archive) |
Action output parameters
The action supports the following output parameters:
signing-request-id: ID of the newly created signing requestsigning-request-web-url: URL of the signing request in SignPathsigned-artifact-download-url: download URL of the signed artifact
Pipeline Policies for GitHub
Available for Pipeline Integrity, Open Source Code Signing.
You can define pipeline policies that restrict source code and build settings.
The available policies specific to GitHub are listed in this section.
There are separate policy sections for GitHub’s CI sytem, GitHub Actions (github-build-policies) and GitHub’s source code management system (github-scm-policies).
Example
github-build-policies:
version: '1.0'
disallow_reruns: false
runners:
require_github_hosted: true
allowed_groups:
- Hardened Runners
github-scm-policies:
version: '1.0'
ruleset_constraints:
- enforced_from: 2025-01-01
allow_bypass_actors: true
rules:
- type: non_fast_forward
- type: pull_request
parameters:
required_approving_review_count: 2
require_last_push_approval: true
github-build-policies
Allows to restrict the GitHub Actions build with the following policies:
| Top-Level Policy | Description |
|---|---|
disallow_reruns |
Set to true to prevent signing builds from re-runs. By enforcing this policy, old, temporarily failed builds cannot be re-run and signed under the false impression that they include recent changes, such as vulnerability fixes. These builds would still be identified by their branch name, e.g. main. |
runners |
Runner-specific settings, see table below. |
Limit to 3 re-runs
Due to performance reasons, SignPath currently allows policy evaluation for up to 3 re-runs of a build. Further re-runs with active policies will fail.
runners section
| Policy | Description |
|---|---|
required_github_hosted |
Set to true to ensure that all jobs of the workflow are executed on Github-hosted runners. |
alllowed_groups |
Provide a list of GitHub runner group names. Ensures that all jobs of the workflow are executed on runners from one of the listed groups. |
github-scm-policies
Allows to define ruleset_constraints for GitHub branch rulesets. All specified constraints must be covered by one or multiple active branch rulesets defined in GitHub. Multiple ruleset_constraints with different parameters can be defined.
How ruleset constraints map to GitHub ruleset rules
GitHub allows you to define branch rulesets, both for repositories and at an organization level. Each branch ruleset defines a set of rules and, optionally, a set of bypass actors.
SignPath allows you to define ruleset contraints. Every rule in a ruleset constraint defined in SignPath’s policies must be fulfilled by at least one rule in a branch ruleset on GitHub. You can define whether bypass actors are allowed and whether the constraint has to be continually fulfilled (see below).
Example:
For example, the following GitHub branch rulesets would fulfill all of the defined ruleset constraints:
- The
non_fast_forwardconstraint is covered by Ruleset 1- The
deletionconstraint is covered by Ruleset 1. It would allow bypass actors, but disallowing them is stricter and therefore valid.- The
creationconstraint is covered by Ruleset 2.
SignPath constraints GitHub branch rulesets github-scm-policies: ruleset_constraints: - allow_bypass_actors: false rules: - type: non_fast_forward - allow_bypass_actors: true rules: - type: deletion - type: creationRuleset 1 (does not allow bypass actors)
- non_fast_forward
- deletion
Ruleset 2 (allows bypass actors)
- creation
General parameters for ruleset_constraints
| Parameter | Values | Description |
|---|---|---|
allow_bypass_actors |
boolean | If true, the branch ruleset is allowed to define bypassers |
enforced_from |
CURRENT_BUILD (default), timestamp or EARLIEST |
By default, the constraints are only evaluated at the time of signing (CURRENT_BUILD). When another value is set for enforced_from, the constraints must have been continously fulfilled from the specified date (YAML ISO timestamp) or earliest availability of audit log entries (EARLIEST). |
GitHub export
The SignPath policies are an extension and therefore compatible with the export format in GitHub. You can export a branch ruleset in GitHub, convert it to YAML and then paste the entire
rulessection underruleset_constraintsin your SignPath policies.
About
enforced_fromevaluationDepending on your GitHub subscription, the continuous enforcement of policies is either based on:
- Audit log events for GitHub Enterprise subscriptions. Audit log events are only available for the last 180 days, any prior policy violations will not be detected. Audit Log evaluation requires the SignPath GitHub App to be installed.
- The last modified date of the branch rulesets for all other subscriptions. At least one branch ruleset that has not been modified since the specified timestap must implement the rule.
Supported rules
The following rules are supported:
| Type | Parameters | Description |
|---|---|---|
creation |
Only allow users with bypass permission to create matching refs. | |
update |
Only allow users with bypass permission to update matching refs. | |
deletion |
Only allow users with bypass permissions to delete matching refs. | |
required_linear_history |
Prevent merge commits from being pushed to matching refs. | |
pull_request |
Yes | Require all commits be made to a non-target branch and submitted via a pull request before they can be merged. |
non_fast_forward |
Prevent users with push access from force pushing to refs. | |
code_scanning |
Yes | Choose which tools must provide code scanning results before the reference is updated. When configured, code scanning must be enabled and have results for both the commit and the reference being updated. |
required_signatures |
Require commits to be signed with a GPG key that is verified by GitHub. | |
file_path_restriction |
Yes | Prevent commits that include changes in specified file and folder paths from being pushed to the commit graph. This includes absolute paths that contain file names. |
file_extension_restriction |
Yes | Prevent commits that include files with specified file extensions from being pushed to the commit graph. |
max_file_path_length |
Yes | Prevent commits that include file paths that exceed the specified character limit from being pushed to the commit graph. |
max_file_size |
Yes | Prevent commits with individual files that exceed the specified limit from being pushed to the commit graph. |
copilot_code_review |
Yes | Request Copilot code review for new pull requests automatically if the author has access to Copilot code review and their premium requests quota has not reached the limit. |
pull_request
Require all commits be made to a non-target branch and submitted via a pull request before they can be merged.
The following parameters are supported:
| Parameter | Description |
dismiss_stale_reviews_on_push(boolean) |
New, reviewable commits pushed will dismiss previous pull request review approvals. |
require_code_owner_review(boolean) |
Require an approving review in pull requests that modify files that have a designated code owner. |
require_last_push_approval(boolean) |
Whether the most recent reviewable push must be approved by someone other than the person who pushed it. |
required_approving_review_count(integer) |
The number of approving reviews that are required before a pull request can be merged. Note: The value defines a required minimum. Higher values are accepted. |
required_review_thread_resolution(boolean) |
All conversations on code must be resolved before a pull request can be merged. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: pull_request
parameters:
dismiss_stale_reviews_on_push: true
require_code_owner_review: true
require_last_push_approval: true
required_approving_review_count: 1
required_review_thread_resolution: true
code_scanning
Choose which tools must provide code scanning results before the reference is updated. When configured, code scanning must be enabled and have results for both the commit and the reference being updated.
The following parameters are supported:
| Parameter | Description | Properties | ||||||||||||
code_scanning_tools(object array; required) |
Tools that must provide code scanning results for this rule to pass. |
|
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: code_scanning
parameters:
code_scanning_tools:
- alerts_threshold: all
security_alerts_threshold: all
tool: CodeQL
file_path_restriction
Prevent commits that include changes in specified file and folder paths from being pushed to the commit graph. This includes absolute paths that contain file names.
The following parameters are supported:
| Parameter | Description |
restricted_file_paths(string array; required) |
The file paths that are restricted from being pushed to the commit graph. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: file_path_restriction
parameters:
restricted_file_paths:
- 'src/config/local.env'
file_extension_restriction
Prevent commits that include files with specified file extensions from being pushed to the commit graph.
The following parameters are supported:
| Parameter | Description |
restricted_file_extensions(string array; required) |
The file extensions that are restricted from being pushed to the commit graph. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: file_extension_restriction
parameters:
restricted_file_extensions:
- '.sql'
max_file_path_length
Prevent commits that include file paths that exceed the specified character limit from being pushed to the commit graph.
The following parameters are supported:
| Parameter | Description |
max_file_path_length(integer; required) |
The maximum amount of characters allowed in file paths. Note: The value defines a required maximum. Lower values are accepted. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: max_file_path_length
parameters:
max_file_path_length: 1024 # characters
max_file_size
Prevent commits with individual files that exceed the specified limit from being pushed to the commit graph.
The following parameters are supported:
| Parameter | Description |
max_file_size(integer; required) |
The maximum file size allowed in megabytes. This limit does not apply to Git Large File Storage (Git LFS). Note: The value defines a required maximum. Lower values are accepted. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: max_file_size
parameters:
max_file_size: 10 # mb
copilot_code_review
Request Copilot code review for new pull requests automatically if the author has access to Copilot code review and their premium requests quota has not reached the limit.
The following parameters are supported:
| Parameter | Description |
review_draft_pull_requests(boolean) |
Copilot automatically reviews draft pull requests before they are marked as ready for review. |
review_on_push(boolean) |
Copilot automatically reviews each new push to the pull request. |
Example:
github-scm-policies:
ruleset_constraints:
- rules:
- type: copilot_code_review
parameters:
review_draft_pull_requests: true
review_on_push: true